# Source: src/js/views/CitationHeaderView.js

    define([
      "jquery",
      "underscore",
      "backbone",
      "views/CitationView",
      "text!templates/citations/citationHeader.html",
    ], function ($, _, Backbone, CitationView, HeaderTemplate) {
      "use strict";

      /**
       * @class CitationHeaderView
       * @classdesc The CitationHeaderView shows a citation information displayed as
       * a header, with expandable author list (if there are more than a certain
       * number of authors).
       * @classcategory Views
       * @extends CitationView
       * @screenshot views/CitationHeaderView.png
       * @since 2.23.0
       * @constructor
       */
      var CitationHeaderView = CitationView.extend(
        /** @lends CitationHeaderView.prototype */ {
          /**
           * The name of this type of view
           * @type {string}
           */
          type: "CitationHeader",

          /**
           * See {@link CitationView#className}
           */
          className: "citation header",

          /**
           * When there are more than this many authors, then this number of authors
           * will always be displayed, and the rest will be viewable with a click.
           * The last author will always be displayed.
           * @type {number}
           * @default 20
           */
          maxAuthors: 20,

          /**
           * See {@link CitationView#styles}. This view only uses the header style.
           * @type {Object}
           */
          styles: {
            header: {
              full: {
                template: _.template(HeaderTemplate), //
                render: "renderHeader",
              },
            },
          },

          /**
           * Override the CitationView style to use the header style.
           * @see {@link CitationView#style}
           */
          style: "header",

          /**
           * Override the CitationView context to use the full context.
           * @see {@link CitationView#context}
           */
          context: "full",

          /**
           * Never create a link for the citation header.
           * See {@link CitationView#createLink}
           */
          createLink: false,

          /**
           * Never create a link for the citation header title.
           * See {@link CitationView#createTitleLink}
           */
          createTitleLink: false,

          /**
           * IDs used in the template to identify the elements that will be
           * manipulated by this view to make the author list collapsible.
           * @type {Object}
           * @property {string} grp1 - The ID of the first group of authors
           * @property {string} grp2 - The ID of the second group of authors
           * @property {string} btn - The ID of the button that will toggle the
           *  visibility of the second group of authors
           * @property {string} last - The ID of the last author
           * @property {string} ellipsis - The ID of the ellipsis that will be
           * displayed when the second group of authors is hidden
           */
          classes: {
            grp1: "CV_authors1",
            grp2: "CV_authors2",
            btn: "CV_show-authors",
            last: "CV_last-author",
            ellipsis: "CV_ellipsis",
          },

          /**
           * Tracks whether the list of authors is open or closed. This will be set
           * automatically when the button is clicked. Set to true when initializing
           * the view to initially render the list open.
           * @type {boolean}
           */
          authorListIsOpen: false,

          /**
           * Render the citation header. Called by {@link CitationView#render}.
           * @param {Object} options - Options to pass to the render method
           * @param {string} options.style - The style to use for rendering
           */
          renderHeader: function (options, template) {
            const authors = options.originArray.map((author) => {
              return this.CSLNameToFullNameStr(author);
            });
            // Split the authors into two groups, one with the maximum number of
            // authors configured (including the last author), and one with the
            // rest.
            const numAuthors = (this.numAuthors = authors.length);
            const maxAuthors = (this.maxAuthors = this.maxAuthors || numAuthors);
            const authorsGrp1 = (this.authorsGrp1 = authors.slice(0, maxAuthors));
            const authorsGrp2 = (this.authorsGrp2 = authors.slice(maxAuthors));
            const numAuthorsGrp2 = (this.numAuthorsGrp2 = authorsGrp2.length);

            // Create a text string for both groups of authors.
            let grp1Str = "";
            let grp2Str = "";
            let lastAuthStr = "";

            if (numAuthors === 0) {
              // Keep the strings empty if there are no authors.
            } else if (numAuthors === 1) {
              // If there is only one author, just show the name.
              grp1Str = authorsGrp1[0];
            } else if (numAuthors === 2) {
              // If there are two authors, separate with and.
              grp1Str = authorsGrp1.join(" and ");
            } else if (numAuthors <= maxAuthors) {
              // If there are less than maxAuthors, separate with commas and and.
              grp1Str = authorsGrp1.slice(0, -1).join(", ");
              grp1Str += ", and " + authorsGrp1.slice(-1);
            } else {
              // Move the last author from grp2 into its own variable
              const lastAuthor = authorsGrp2.pop();
              // Move the last author from grp1 to the start of grp2
              authorsGrp2.unshift(authorsGrp1.pop());
              // Grp1 string should be separated by just commas, including a comma
              // at the very end.
              grp1Str = authorsGrp1.join(", ") + ", ";
              // Store the "and" with the last author
              lastAuthStr = " and " + lastAuthor;
              // grp2 also just commas
              grp2Str = authorsGrp2.join(", ");
            }
            options.authorsGrp1 = grp1Str;
            options.authorsGrp2 = grp2Str;
            options.lastAuthor = lastAuthStr;

            // Pass classes that we can use to refer to all the elements we need to
            // manipulate.
            options.classes = this.classes;

            this.el.innerHTML = template(options);

            // Select all the elements
            const els = (this.els = {});
            Object.keys(options.classes).forEach((key) => {
              els[key] = this.el.querySelector(`.${options.classes[key]}`);
            });

            // If there are fewer than maxAuthors, then the template will not render
            // a button or ellipsis. Otherwise, set the open/close behavior
            if (els.btn) {
              els.btn.addEventListener("click", this.toggleList.bind(this));
            }
            if (els.ellipsis) {
              els.ellipsis.addEventListener("click", this.openList.bind(this));
            }
            if (els.ellipsis || els.btn) {
              // Set the list to be open or closed based on the initial setting of
              // in the view
              if (this.authorListIsOpen) {
                this.openList();
              } else {
                this.closeList();
              }
            }
          },

          /**
           * Open the list of authors, showing all authors.
           */
          openList: function () {
            try {
              const els = this.els;
              els.grp2.style.display = "";
              els.btn.innerHTML = "- Show fewer authors";
              els.ellipsis.style.display = "none";
              // Reorder the elements
              els.btn.parentNode.append(
                els.grp1,
                els.grp2,
                els.last,
                els.btn,
                els.ellipsis
              );
              this.authorListIsOpen = true;
            } catch (error) {
              console.log(
                "Failed to expand an author list in the citation view.",
                error
              );
            }
          },

          /**
           * Close the list of authors, showing only the first group of authors. The
           * last author will always be shown.
           */
          closeList: function () {
            try {
              const els = this.els;
              const no = this.numAuthorsGrp2 || "";
              els.grp2.style.display = "none";
              els.btn.innerHTML = `+ Show ${no} more authors`;
              els.ellipsis.style.display = "";
              // Reorder elements
              els.btn.parentNode.append(
                els.grp1,
                els.ellipsis,
                els.last,
                els.btn,
                els.grp2
              );
              this.authorListIsOpen = false;
            } catch (error) {
              console.log(
                "Failed to collapse an author list in the citation view.",
                error
              );
            }
          },

          /**
           * Toggle the visibility of the second group of authors. If the second
           * group is visible, then it will be hidden. If the second group is
           * hidden, then it will be shown.
           */
          toggleList: function () {
            if (this.authorListIsOpen) {
              this.closeList();
            } else {
              this.openList();
            }
          },
        }
      );

      return CitationHeaderView;
    });