Source: src/js/views/schemaOrg/SchemaOrgView.js

"use strict";

define([
  "backbone",
  "models/schemaOrg/SchemaOrg",
  "text!templates/jsonld.txt",
], (Backbone, SchemaOrg, jsonLDTemplate) => {
  const SCRIPT_TYPE = "application/ld+json";
  const JSON_LD_ID = "jsonld";
  /**
   * @class SchemaOrgView
   * @classdesc Inserts and updates the Schema.org JSON-LD script tag in the
   * head of the document. This view will only work if the JSON-LD feature is
   * enabled in the MetacatUI configuration. Otherwise, no JSON-LD script tag
   * will be inserted into the head of the document.
   * @classcategory Views/Maps
   * @name SchemaOrgView
   * @augments Backbone.View
   * @since 2.32.0
   * @constructs SchemaOrgView
   */
  const SchemaOrgView = Backbone.View.extend(
    /** @lends SchemaOrgView.prototype */ {
      /** @inheritdoc */
      initialize() {
        if (!this.isEnabled()) return;
        this.model = new SchemaOrg();
        this.stopListening();
        this.listenTo(this.model, "change", this.updateJsonldEl);
      },

      /**
       * Default JSON LD to use for pages that don't have a specific schema.
       * @type {string}
       */
      template: jsonLDTemplate,

      /**
       * Checks if the JSON-LD feature is enabled in the MetacatUI configuration.
       * @returns {boolean} True if the JSON-LD feature is enabled, false otherwise.
       */
      isEnabled() {
        return MetacatUI.appModel.get("isJSONLDEnabled");
      },

      /** @inheritdoc */
      render() {
        if (!this.isEnabled()) return;
        this.removeExistingJsonldEls();
        this.addJsonldEl();
      },

      /**
       * Updates the JSON-LD script tag in the head of the document based on the
       * type of page being viewed.
       * @param {"Dataset"|"DataCatalog"} type - The type of page being viewed.
       * If neither "Dataset" nor "DataCatalog" is provided, the schema will be
       * set to the default schema.
       * @param {object} model - The model to use for the schema.
       * @since 2.32.0
       */
      setSchema(type, model = null) {
        if (!this.isEnabled()) return;
        this.model.setSchema(type, model);
      },

      /**
       * Sets the schema based on a template.
       */
      setSchemaFromTemplate() {
        if (!this.isEnabled()) return;
        const template = this.template.trim();
        if (!template) return;
        if (typeof template === "string" && template.length > 0) {
          this.model.setSchemaFromTemplate(template);
        }
      },

      /**
       * Create the JSON LD element to insert into the head of the document.
       * @returns {HTMLScriptElement} The JSON LD element.
       */
      createJsonldEl() {
        const jsonldEl = document.createElement("script");
        jsonldEl.type = SCRIPT_TYPE;
        jsonldEl.id = JSON_LD_ID;
        this.jsonldEl = jsonldEl;
        return jsonldEl;
      },

      /**
       * Updates the JSON-LD script tag in the head of the document based on the
       * model values.
       */
      updateJsonldEl() {
        if (!this.isEnabled()) return;
        let el = this.jsonldEl;
        if (!el) {
          el = this.addJsonldEl();
        }
        const text = this.model.serialize();
        el.text = text;
      },

      /**
       * Inserts the JSON-LD script tag into the head of the document.
       * @returns {HTMLScriptElement} The JSON-LD element.
       */
      addJsonldEl() {
        if (!this.isEnabled()) return null;
        const el = this.createJsonldEl();
        document.head.appendChild(el);
        return el;
      },

      /**
       * Get all the existing JSON-LD elements in the head of the document.
       * @returns {NodeListOf<HTMLScriptElement>} The existing JSON-LD elements.
       */
      getExistingJsonldEls() {
        return document.head.querySelectorAll(`script[type="${SCRIPT_TYPE}"]`);
      },

      /**
       * Removes any existing JSON-LD elements from the head of the document.
       */
      removeExistingJsonldEls() {
        const els = this.getExistingJsonldEls();
        els.forEach((el) => {
          document.head.removeChild(el);
        });
        this.jsonldEl = null;
      },

      /** What to do when the view is closed. */
      onClose() {
        this.removeExistingJsonldEls();
        this.stopListening();
        this.model.destroy();
      },
    },
  );

  return SchemaOrgView;
});