diff --git a/src/js/views/MetadataView.js b/src/js/views/MetadataView.js index 8083d2397..19d42fa7b 100644 --- a/src/js/views/MetadataView.js +++ b/src/js/views/MetadataView.js @@ -38,7 +38,7 @@ define([ "text!templates/metaTagsHighwirePress.html", "uuid", "views/MetricView", -], function ( +], ( $, $ui, _, @@ -78,18 +78,18 @@ define([ metaTagsHighwirePressTemplate, uuid, MetricView, -) { +) => { "use strict"; /** * @class MetadataView * @classdesc A human-readable view of a science metadata file * @classcategory Views - * @extends Backbone.View - * @constructor + * @augments Backbone.View + * @class * @screenshot views/MetadataView.png */ - var MetadataView = Backbone.View.extend( + const MetadataView = Backbone.View.extend( /** @lends MetadataView.prototype */ { subviews: [], @@ -116,7 +116,7 @@ define([ type: "Metadata", - //Templates + // Templates template: _.template(MetadataTemplate), alertTemplate: _.template(AlertTemplate), doiTemplate: _.template(PublishDoiTemplate), @@ -156,7 +156,7 @@ define([ "click #save-metadata-prov": "saveProv", }, - initialize: function (options) { + initialize(options) { if (options === undefined || !options) var options = {}; this.pid = @@ -168,13 +168,13 @@ define([ }, // Render the main metadata view - render: function () { + render() { this.stopListening(); MetacatUI.appModel.set("headerType", "default"); // this.showLoading("Loading..."); - //Reset various properties of this view first + // Reset various properties of this view first this.classMap = new Array(); this.subviews = new Array(); this.model.set(this.model.defaults); @@ -185,18 +185,18 @@ define([ this.listenTo(MetacatUI.appUserModel, "change:loggedIn", this.render); - //Listen to when the metadata has been rendered + // Listen to when the metadata has been rendered this.once("metadataLoaded", function () { this.createAnnotationViews(); this.insertMarkdownViews(); }); - //Listen to when the package table has been rendered + // Listen to when the package table has been rendered this.once("dataPackageRendered", function () { - var packageTableContainer = this.$("#data-package-container"); + const packageTableContainer = this.$("#data-package-container"); $(packageTableContainer).children(".loading").remove(); - //Scroll to the element on the page that is in the hash fragment (if there is one) + // Scroll to the element on the page that is in the hash fragment (if there is one) this.scrollToFragment(); }); @@ -211,11 +211,11 @@ define([ * table view, if there is one. * @param {string} pid - The PID of the resource map */ - getDataPackage: function (pid) { - //Create a DataONEObject model to use in the DataPackage collection. - var dataOneObject = new ScienceMetadata({ id: this.model.get("id") }); + getDataPackage(pid) { + // Create a DataONEObject model to use in the DataPackage collection. + const dataOneObject = new ScienceMetadata({ id: this.model.get("id") }); - var view = this; + const view = this; // Create a new data package with this id this.dataPackage = new DataPackage([dataOneObject], { id: pid }); @@ -235,7 +235,7 @@ define([ this.listenToOnce(this.dataPackage, "complete", function () { this.dataPackageSynced = true; this.trigger("changed:dataPackageSynced"); - var dataPackageView = _.findWhere(this.subviews, { + const dataPackageView = _.findWhere(this.subviews, { type: "DataPackage", }); if (dataPackageView) { @@ -244,16 +244,16 @@ define([ } }); - this.listenToOnce(this.dataPackage, "fetchFailed", function () { + this.listenToOnce(this.dataPackage, "fetchFailed", () => { view.dataPackageSynced = false; // stop listening to the fetch complete view.stopListening(view.dataPackage, "complete"); - //Remove the loading elements + // Remove the loading elements view.$(view.tableContainer).find(".loading").remove(); - //Show an error message + // Show an error message MetacatUI.appView.showAlert( "Error retrieving files for this data package.", "alert-error", @@ -281,15 +281,15 @@ define([ * Retrieves information from the index about this object, given the id (passed from the URL) * When the object info is retrieved from the index, we set up models depending on the type of object this is */ - getModel: function (pid) { - //Get the pid and sid - if (typeof pid === "undefined" || !pid) var pid = this.pid; + getModel(pid) { + // Get the pid and sid + if (typeof pid === "undefined" || !pid) var { pid } = this; if (typeof this.seriesId !== "undefined" && this.seriesId) var sid = this.seriesId; - //Get the package ID + // Get the package ID this.model.set({ id: pid, seriesId: sid }); - var model = this.model; + const { model } = this; this.listenToOnce(model, "sync", function () { if ( @@ -299,94 +299,89 @@ define([ this.model = model; this.renderMetadata(); } else if (this.model.get("formatType") == "DATA") { - //Get the metadata pids that document this data object - var isDocBy = this.model.get("isDocumentedBy"); + // Get the metadata pids that document this data object + const isDocBy = this.model.get("isDocumentedBy"); - //If there is only one metadata pid that documents this data object, then + // If there is only one metadata pid that documents this data object, then // get that metadata model for this view. if (isDocBy && isDocBy.length == 1) { this.navigateWithFragment(_.first(isDocBy), this.pid); return; } - //If more than one metadata doc documents this data object, it is most likely + // If more than one metadata doc documents this data object, it is most likely // multiple versions of the same metadata. So we need to find the latest version. - else if (isDocBy && isDocBy.length > 1) { - var view = this; - - require([ - "collections/Filters", - "collections/SolrResults", - ], function (Filters, SolrResults) { - //Create a search for the metadata docs that document this data object - var searchFilters = new Filters([ - { - values: isDocBy, - fields: ["id", "seriesId"], - operator: "OR", - fieldsOperator: "OR", - matchSubstring: false, - }, - ]), - //Create a list of search results - searchResults = new SolrResults([], { - rows: isDocBy.length, - query: searchFilters.getQuery(), - fields: "obsoletes,obsoletedBy,id", - }); + if (isDocBy && isDocBy.length > 1) { + const view = this; + + require(["collections/Filters", "collections/SolrResults"], ( + Filters, + SolrResults, + ) => { + // Create a search for the metadata docs that document this data object + const searchFilters = new Filters([ + { + values: isDocBy, + fields: ["id", "seriesId"], + operator: "OR", + fieldsOperator: "OR", + matchSubstring: false, + }, + ]); + // Create a list of search results + const searchResults = new SolrResults([], { + rows: isDocBy.length, + query: searchFilters.getQuery(), + fields: "obsoletes,obsoletedBy,id", + }); - //When the search results are returned, process those results - view.listenToOnce( - searchResults, - "sync", - function (searchResults) { - //Keep track of the latest version of the metadata doc(s) - var latestVersions = []; - - //Iterate over each search result and find the latest version of each metadata version chain - searchResults.each(function (searchResult) { - //If this metadata isn't obsoleted by another object, it is the latest version - if (!searchResult.get("obsoletedBy")) { - latestVersions.push(searchResult.get("id")); - } - //If it is obsoleted by another object but that newer object does not document this data, then this is the latest version - else if ( - !_.contains(isDocBy, searchResult.get("obsoletedBy")) - ) { - latestVersions.push(searchResult.get("id")); - } - }, view); - - //If at least one latest version was found (should always be the case), - if (latestVersions.length) { - //Set that metadata pid as this view's pid and get that metadata model. - // TODO: Support navigation to multiple metadata docs. This should be a rare occurence, but - // it is possible that more than one metadata version chain documents a data object, and we need - // to show the user that the data is involved in multiple datasets. - view.navigateWithFragment(latestVersions[0], view.pid); + // When the search results are returned, process those results + view.listenToOnce(searchResults, "sync", (searchResults) => { + // Keep track of the latest version of the metadata doc(s) + const latestVersions = []; + + // Iterate over each search result and find the latest version of each metadata version chain + searchResults.each((searchResult) => { + // If this metadata isn't obsoleted by another object, it is the latest version + if (!searchResult.get("obsoletedBy")) { + latestVersions.push(searchResult.get("id")); } - //If a latest version wasn't found, which should never happen, but just in case, default to the - // last metadata pid in the isDocumentedBy field (most liekly to be the most recent since it was indexed last). - else { - view.navigateWithFragment(_.last(isDocBy), view.pid); + // If it is obsoleted by another object but that newer object does not document this data, then this is the latest version + else if ( + !_.contains(isDocBy, searchResult.get("obsoletedBy")) + ) { + latestVersions.push(searchResult.get("id")); } - }, - ); + }, view); + + // If at least one latest version was found (should always be the case), + if (latestVersions.length) { + // Set that metadata pid as this view's pid and get that metadata model. + // TODO: Support navigation to multiple metadata docs. This should be a rare occurence, but + // it is possible that more than one metadata version chain documents a data object, and we need + // to show the user that the data is involved in multiple datasets. + view.navigateWithFragment(latestVersions[0], view.pid); + } + // If a latest version wasn't found, which should never happen, but just in case, default to the + // last metadata pid in the isDocumentedBy field (most liekly to be the most recent since it was indexed last). + else { + view.navigateWithFragment(_.last(isDocBy), view.pid); + } + }); - //Send the query to the Solr search service + // Send the query to the Solr search service searchResults.query(); }); return; - } else { - this.noMetadata(this.model); } + this.noMetadata(this.model); } else if (this.model.get("formatType") == "RESOURCE") { - var packageModel = new Package({ id: this.model.get("id") }); + const packageModel = new Package({ id: this.model.get("id") }); packageModel.on( "complete", function () { - var metadata = packageModel.getMetadata(); + const metadata = packageModel.getMetadata(); if (!metadata) { this.noMetadata(packageModel); @@ -404,23 +399,23 @@ define([ return; } - //Get the package information + // Get the package information this.getPackageDetails(model.get("resourceMap")); }); - //Listen to 404 and 401 errors when we get the metadata object + // Listen to 404 and 401 errors when we get the metadata object this.listenToOnce(model, "404", this.showNotFound); this.listenToOnce(model, "401", this.showIsPrivate); - //Fetch the model + // Fetch the model model.getInfo(); }, - renderMetadata: function () { - var pid = this.model.get("id"); + renderMetadata() { + const pid = this.model.get("id"); this.hideLoading(); - //Load the template which holds the basic structure of the view + // Load the template which holds the basic structure of the view this.$el.html(this.template()); this.$(this.tableContainer).html( this.loadingTemplate({ @@ -428,11 +423,11 @@ define([ }), ); - //Insert the breadcrumbs + // Insert the breadcrumbs this.insertBreadcrumbs(); - //Insert the citation + // Insert the citation this.insertCitation(); - //Insert the data source logo + // Insert the data source logo this.insertDataSource(); // is this the latest version? (includes DOI link when needed) this.showLatestVersion(); @@ -443,11 +438,11 @@ define([ // If we're displaying the metrics well then display copy citation and edit button // inside the well if (MetacatUI.appModel.get("displayDatasetMetrics")) { - //Insert Metrics Stats into the dataset landing pages + // Insert Metrics Stats into the dataset landing pages this.insertMetricsControls(); } - //Show loading icon in metadata section + // Show loading icon in metadata section this.$(this.metadataContainer).html( this.loadingTemplate({ msg: "Retrieving metadata ..." }), ); @@ -461,15 +456,15 @@ define([ MetacatUI.appModel.get("viewServiceUrl") + encodeURIComponent(pid); if (endpoint && typeof endpoint !== "undefined") { - var viewRef = this; - var loadSettings = { + const viewRef = this; + const loadSettings = { url: endpoint, - success: function (response, status, xhr) { + success(response, status, xhr) { try { - //If the user has navigated away from the MetadataView, then don't render anything further + // If the user has navigated away from the MetadataView, then don't render anything further if (MetacatUI.appView.currentView != viewRef) return; - //Our fallback is to show the metadata details from the Solr index + // Our fallback is to show the metadata details from the Solr index if ( status == "error" || !response || @@ -477,7 +472,7 @@ define([ ) viewRef.renderMetadataFromIndex(); else { - //Check for a response that is a 200 OK status, but is an error msg + // Check for a response that is a 200 OK status, but is an error msg if ( response.length < 250 && response.indexOf("Error transforming document") > -1 && @@ -486,8 +481,8 @@ define([ viewRef.renderMetadataFromIndex(); return; } - //Mark this as a metadata doc with no stylesheet, or one that is at least different than usual EML and FGDC - else if (response.indexOf('id="Metadata"') == -1) { + // Mark this as a metadata doc with no stylesheet, or one that is at least different than usual EML and FGDC + if (response.indexOf('id="Metadata"') == -1) { viewRef.$el.addClass("container no-stylesheet"); if (viewRef.model.get("indexed")) { @@ -496,15 +491,15 @@ define([ } } - //Now show the response from the view service + // Now show the response from the view service viewRef.$(viewRef.metadataContainer).html(response); - _.each($(response).find(".entitydetails"), function (entityEl) { - var entityId = $(entityEl).data("id"); + _.each($(response).find(".entitydetails"), (entityEl) => { + const entityId = $(entityEl).data("id"); viewRef.storeEntityPIDs(entityEl, entityId); }); - //If there is no info from the index and there is no metadata doc rendered either, then display a message + // If there is no info from the index and there is no metadata doc rendered either, then display a message if ( viewRef.$el.is(".no-stylesheet") && viewRef.model.get("archived") && @@ -520,7 +515,7 @@ define([ viewRef.trigger("metadataLoaded"); - //Add a map of the spatial coverage + // Add a map of the spatial coverage if (gmaps) viewRef.insertSpatialCoverageMap(); // Injects Clipboard objects into DOM elements returned from the View Service @@ -535,7 +530,7 @@ define([ viewRef.renderMetadataFromIndex(); } }, - error: function (xhr, textStatus, errorThrown) { + error(xhr, textStatus, errorThrown) { viewRef.renderMetadataFromIndex(); }, }; @@ -547,7 +542,7 @@ define([ // Insert the Linked Data into the header of the page. if (MetacatUI.appModel.get("isJSONLDEnabled")) { - var json = this.generateJSONLD(); + const json = this.generateJSONLD(); this.insertJSONLD(json); } @@ -555,76 +550,76 @@ define([ }, /* If there is no view service available, then display the metadata fields from the index */ - renderMetadataFromIndex: function () { - var metadataFromIndex = new MetadataIndex({ + renderMetadataFromIndex() { + const metadataFromIndex = new MetadataIndex({ pid: this.pid, parentView: this, }); this.subviews.push(metadataFromIndex); - //Add the metadata HTML + // Add the metadata HTML this.$(this.metadataContainer).html(metadataFromIndex.render().el); - var view = this; + const view = this; - this.listenTo(metadataFromIndex, "complete", function () { - //Add the package contents + this.listenTo(metadataFromIndex, "complete", () => { + // Add the package contents view.insertPackageDetails(); - //Add a map of the spatial coverage + // Add a map of the spatial coverage if (gmaps) view.insertSpatialCoverageMap(); }); }, - removeCitation: function () { - var citation = "", - citationEl = null; + removeCitation() { + let citation = ""; + let citationEl = null; - //Find the citation element + // Find the citation element if (this.$(".citation").length > 0) { - //Get the text for the citation + // Get the text for the citation citation = this.$(".citation").text(); - //Save this element in the view + // Save this element in the view citationEl = this.$(".citation"); } - //Older versions of Metacat (v2.4.3 and older) will not have the citation class in the XSLT. Find the citation another way + // Older versions of Metacat (v2.4.3 and older) will not have the citation class in the XSLT. Find the citation another way else { - //Find the DOM element with the citation - var wells = this.$(".well"), - viewRef = this; + // Find the DOM element with the citation + const wells = this.$(".well"); + const viewRef = this; - //Find the div.well with the citation. If we never find it, we don't insert the list of contents - _.each(wells, function (well) { + // Find the div.well with the citation. If we never find it, we don't insert the list of contents + _.each(wells, (well) => { if ( (!citationEl && $(well).find("#viewMetadataCitationLink").length > 0) || $(well).children(".row-fluid > .span10 > a") ) { - //Save this element in the view + // Save this element in the view citationEl = well; - //Mark this in the DOM for CSS styling + // Mark this in the DOM for CSS styling $(well).addClass("citation"); - //Save the text of the citation + // Save the text of the citation citation = $(well).text(); } }); - //Remove the unnecessary classes that are used in older versions of Metacat (2.4.3 and older) - var citationText = $(citationEl).find(".span10"); + // Remove the unnecessary classes that are used in older versions of Metacat (2.4.3 and older) + const citationText = $(citationEl).find(".span10"); $(citationText).removeClass("span10").addClass("span12"); } - //Set the document title to the citation + // Set the document title to the citation MetacatUI.appModel.set("title", citation); citationEl.remove(); }, - insertBreadcrumbs: function () { - var breadcrumbs = $(document.createElement("ol")) + insertBreadcrumbs() { + const breadcrumbs = $(document.createElement("ol")) .addClass("breadcrumb") .append( $(document.createElement("li")) @@ -643,12 +638,13 @@ define([ $(document.createElement("a")) .attr( "href", - MetacatUI.root + - "/data" + - (MetacatUI.appModel.get("page") > 0 - ? "/page/" + - (parseInt(MetacatUI.appModel.get("page")) + 1) - : ""), + `${MetacatUI.root}/data${ + MetacatUI.appModel.get("page") > 0 + ? `/page/${ + parseInt(MetacatUI.appModel.get("page")) + 1 + }` + : "" + }`, ) .addClass("search") .text("Search"), @@ -659,7 +655,7 @@ define([ $(document.createElement("a")) .attr( "href", - MetacatUI.root + "/view/" + encodeURIComponent(this.pid), + `${MetacatUI.root}/view/${encodeURIComponent(this.pid)}`, ) .addClass("inactive") .text("Metadata"), @@ -671,11 +667,11 @@ define([ $(document.createElement("a")) .attr( "href", - MetacatUI.root + - "/data/page/" + - (MetacatUI.appModel.get("page") > 0 + `${MetacatUI.root}/data/page/${ + MetacatUI.appModel.get("page") > 0 ? parseInt(MetacatUI.appModel.get("page")) + 1 - : ""), + : "" + }`, ) .attr("title", "Back") .addClass("back") @@ -693,16 +689,16 @@ define([ /* * When the metadata object doesn't exist, display a message to the user */ - showNotFound: function () { - //If the model was found, exit this function + showNotFound() { + // If the model was found, exit this function if (!this.model.get("notFound")) { return; } try { - //Check if a query string was in the URL and if so, try removing it in the identifier + // Check if a query string was in the URL and if so, try removing it in the identifier if (this.model.get("id").match(/\?\S+\=\S+/g) && !this.findTries) { - let newID = this.model.get("id").replace(/\?\S+\=\S+/g, ""); + const newID = this.model.get("id").replace(/\?\S+\=\S+/g, ""); this.onClose(); this.model.set("id", newID); this.pid = newID; @@ -714,38 +710,38 @@ define([ console.warn("Caught error while determining query string", e); } - //Construct a message that shows this object doesn't exist - var msg = - "

Nothing was found.

" + - "

The dataset identifier '" + - Utilities.encodeHTML(this.model.get("id")) + - "' " + - "does not exist or it may have been removed. Search for " + - "datasets that mention " + - Utilities.encodeHTML(this.model.get("id")) + - "

"; + // Construct a message that shows this object doesn't exist + const msg = + `

Nothing was found.

` + + `

The dataset identifier '${Utilities.encodeHTML( + this.model.get("id"), + )}' ` + + `does not exist or it may have been removed. Search for ` + + `datasets that mention ${Utilities.encodeHTML( + this.model.get("id"), + )}

`; - //Remove the loading message + // Remove the loading message this.hideLoading(); - //Show the not found error message + // Show the not found error message this.showError(msg); - //Add the pid to the link href. Add via JS so it is Attribute-encoded to prevent XSS attacks + // Add the pid to the link href. Add via JS so it is Attribute-encoded to prevent XSS attacks this.$("#metadata-view-not-found-message a").attr( "href", - MetacatUI.root + - "/data/query=" + - encodeURIComponent(this.model.get("id")), + `${MetacatUI.root}/data/query=${encodeURIComponent( + this.model.get("id"), + )}`, ); }, /* * When the metadata object is private, display a message to the user */ - showIsPrivate: function () { - //If we haven't checked the logged-in status of the user yet, wait a bit - //until we show a 401 msg, in case this content is their private content + showIsPrivate() { + // If we haven't checked the logged-in status of the user yet, wait a bit + // until we show a 401 msg, in case this content is their private content if (!MetacatUI.appUserModel.get("checked")) { this.listenToOnce( MetacatUI.appUserModel, @@ -755,7 +751,7 @@ define([ return; } - //If the user is logged in, the message will display that this dataset is private. + // If the user is logged in, the message will display that this dataset is private. if (MetacatUI.appUserModel.get("loggedIn")) { var msg = '' + " This is a private dataset."; } - //If the user isn't logged in, display a log in link. + // If the user isn't logged in, display a log in link. else { var msg = - '' + - '' + - '' + - " This is a private dataset. If you believe you have permission " + - 'to access this dataset, then sign in.'; + `` + + `` + + `` + + ` This is a private dataset. If you believe you have permission ` + + `to access this dataset, then sign in.`; } - //Remove the loading message + // Remove the loading message this.hideLoading(); - //Show the not found error message + // Show the not found error message this.showError(msg); }, - getPackageDetails: function (packageIDs) { - var completePackages = 0; + getPackageDetails(packageIDs) { + let completePackages = 0; - //This isn't a package, but just a lonely metadata doc... + // This isn't a package, but just a lonely metadata doc... if (!packageIDs || !packageIDs.length) { - var thisPackage = new Package({ id: null, members: [this.model] }); + const thisPackage = new Package({ id: null, members: [this.model] }); thisPackage.flagComplete(); this.packageModels = [thisPackage]; this.insertPackageDetails(thisPackage, { @@ -801,32 +795,30 @@ define([ _.each( packageIDs, function (thisPackageID, i) { - //Create a model representing the data package - var thisPackage = new Package({ id: thisPackageID }); + // Create a model representing the data package + const thisPackage = new Package({ id: thisPackageID }); - //Listen for any parent packages + // Listen for any parent packages this.listenToOnce( thisPackage, "change:parentPackageMetadata", this.insertParentLink, ); - //When the package info is fully retrieved + // When the package info is fully retrieved this.listenToOnce( thisPackage, "complete", function (thisPackage) { - //When all packages are fully retrieved + // When all packages are fully retrieved completePackages++; if (completePackages >= packageIDs.length) { - var latestPackages = _.filter( + const latestPackages = _.filter( this.packageModels, - function (m) { - return !_.contains(packageIDs, m.get("obsoletedBy")); - }, + (m) => !_.contains(packageIDs, m.get("obsoletedBy")), ); - //Set those packages as the most recent package + // Set those packages as the most recent package this.packageModels = latestPackages; this.insertPackageDetails(latestPackages); @@ -834,13 +826,13 @@ define([ }, ); - //Save the package in the view + // Save the package in the view this.packageModels.push(thisPackage); - //Make sure we get archived content, too + // Make sure we get archived content, too thisPackage.set("getArchivedMembers", true); - //Get the members + // Get the members thisPackage.getMembers({ getParentMetadata: true }); }, this, @@ -848,19 +840,19 @@ define([ } }, - alterMarkup: function () { - //Find the taxonomic range and give it a class for styling - for older versions of Metacat only (v2.4.3 and older) + alterMarkup() { + // Find the taxonomic range and give it a class for styling - for older versions of Metacat only (v2.4.3 and older) if (!this.$(".taxonomicCoverage").length) this.$('h4:contains("Taxonomic Range")') .parent() .addClass("taxonomicCoverage"); - //Remove ecogrid links and replace them with workable links + // Remove ecogrid links and replace them with workable links this.replaceEcoGridLinks(); - //Find the tab links for attribute names - this.$(".attributeListTable tr a").on("shown", function (e) { - //When the attribute link is clicked on, highlight the tab as active + // Find the tab links for attribute names + this.$(".attributeListTable tr a").on("shown", (e) => { + // When the attribute link is clicked on, highlight the tab as active $(e.target) .parents(".attributeListTable") .find(".active") @@ -868,7 +860,7 @@ define([ $(e.target).parents("tr").first().addClass("active"); }); - //Mark the first row in each attribute list table as active since the first attribute is displayed at first + // Mark the first row in each attribute list table as active since the first attribute is displayed at first this.$(".attributeListTable tr:first-child()").addClass("active"); // Add explanation text to the alternate identifier @@ -882,7 +874,7 @@ define([ * @returns {jQuery} The jQuery object for the icon element. * @since 2.26.0 */ - renderAltIdentifierHelpText: function () { + renderAltIdentifierHelpText() { try { // Find the HTML element that contains the alternate identifier. const altIdentifierLabel = this.$( @@ -920,17 +912,17 @@ define([ /* * Inserts a table with all the data package member information and sends the call to display annotations */ - insertPackageDetails: function (packages, options) { + insertPackageDetails(packages, options) { if (typeof options === "undefined") { var options = {}; } - //Don't insert the package details twice - var view = this; - var tableEls = this.$(view.tableContainer).children().not(".loading"); + // Don't insert the package details twice + const view = this; + const tableEls = this.$(view.tableContainer).children().not(".loading"); if (tableEls.length > 0) return; - //wait for the metadata to load - var metadataEls = this.$(view.metadataContainer).children(); + // wait for the metadata to load + const metadataEls = this.$(view.metadataContainer).children(); if (!metadataEls.length || metadataEls.first().is(".loading")) { this.once("metadataLoaded", function () { view.insertPackageDetails(this.packageModels, options); @@ -940,26 +932,26 @@ define([ if (!packages) var packages = this.packageModels; - //Get the entity names from this page/metadata + // Get the entity names from this page/metadata this.getEntityNames(packages); _.each( packages, function (packageModel) { - //If the package model is not complete, don't do anything + // If the package model is not complete, don't do anything if (!packageModel.complete) return; - //Insert a package table for each package in viewRef dataset - var nestedPckgs = packageModel.getNestedPackages(), - nestedPckgsToDisplay = []; + // Insert a package table for each package in viewRef dataset + const nestedPckgs = packageModel.getNestedPackages(); + let nestedPckgsToDisplay = []; - //If this metadata is not archived, filter out archived packages + // If this metadata is not archived, filter out archived packages if (!this.model.get("archived")) { - nestedPckgsToDisplay = _.reject(nestedPckgs, function (pkg) { - return pkg.get("archived"); - }); + nestedPckgsToDisplay = _.reject(nestedPckgs, (pkg) => + pkg.get("archived"), + ); } else { - //Display all packages is this metadata is archived + // Display all packages is this metadata is archived nestedPckgsToDisplay = nestedPckgs; } @@ -971,16 +963,16 @@ define([ ) ) { var title = packageModel.get("id") - ? 'Package: ' + - packageModel.get("id") + - "" + ? `Package: ${packageModel.get( + "id", + )}` : ""; - options.title = "Files in this dataset " + title; + options.title = `Files in this dataset ${title}`; options.nested = true; this.insertPackageTable(packageModel, options); } } else { - //If this metadata is not archived, then don't display archived packages + // If this metadata is not archived, then don't display archived packages if ( !( !this.model.get("archived") && @@ -988,24 +980,24 @@ define([ ) ) { var title = packageModel.get("id") - ? 'Package: ' + - packageModel.get("id") + - "" + ? `Package: ${packageModel.get( + "id", + )}` : ""; - options.title = "Files in this dataset " + title; + options.title = `Files in this dataset ${title}`; this.insertPackageTable(packageModel, options); } } - //Remove the extra download button returned from the XSLT since the package table will have all the download links + // Remove the extra download button returned from the XSLT since the package table will have all the download links $("#downloadPackage").remove(); }, this, ); - //If this metadata doc is not in a package, but is just a lonely metadata doc... + // If this metadata doc is not in a package, but is just a lonely metadata doc... if (!packages.length) { - var packageModel = new Package({ + const packageModel = new Package({ members: [this.model], }); packageModel.complete = true; @@ -1014,7 +1006,7 @@ define([ this.insertPackageTable(packageModel, options); } - //Insert the data details sections + // Insert the data details sections this.insertDataDetails(); // Get data package, if there is one, before checking write permissions @@ -1028,20 +1020,20 @@ define([ try { // Get the most recent package to display the provenance graphs if (packages.length) { - //Find the most recent Package model and fetch it + // Find the most recent Package model and fetch it let mostRecentPackage = _.find( packages, (p) => !p.get("obsoletedBy"), ); - //If all of the packages are obsoleted, then use the last package in the array, + // If all of the packages are obsoleted, then use the last package in the array, // which is most likely the most recent. /** @todo Use the DataONE version API to find the most recent package in the version chain */ if (!mostRecentPackage) { mostRecentPackage = packages[packages.length - 1]; } - //Get the data package only if it is not the same as the previously fetched package + // Get the data package only if it is not the same as the previously fetched package if (mostRecentPackage.get("id") != packages[0].get("id")) this.getDataPackage(mostRecentPackage.get("id")); } @@ -1052,16 +1044,16 @@ define([ ); } - //Initialize tooltips in the package table(s) + // Initialize tooltips in the package table(s) this.$(".tooltip-this").tooltip(); return this; }, - insertPackageTable: function (packageModel, options) { - var view = this; + insertPackageTable(packageModel, options) { + const view = this; if (this.dataPackage == null || !this.dataPackageSynced) { - this.listenToOnce(this, "changed:dataPackageSynced", function () { + this.listenToOnce(this, "changed:dataPackageSynced", () => { view.insertPackageTable(packageModel, options); }); return; @@ -1086,39 +1078,39 @@ define([ nested = false, disablePackageDownloads = false; - //** Draw the package table **// - var tableView = new DataPackageView({ + //* * Draw the package table **// + const tableView = new DataPackageView({ edit: false, dataPackage: this.dataPackage, currentlyViewing: this.pid, dataEntities: this.entities, - disablePackageDownloads: disablePackageDownloads, + disablePackageDownloads, parentView: this, - title: title, + title, packageTitle: this.model.get("title"), - nested: nested, + nested, metricsModel: this.metricsModel, }); - //Get the package table container - var tablesContainer = this.$(this.tableContainer); + // Get the package table container + const tablesContainer = this.$(this.tableContainer); - //After the first table, start collapsing them - var numTables = $(tablesContainer).find( + // After the first table, start collapsing them + const numTables = $(tablesContainer).find( "table.download-contents", ).length; if (numTables == 1) { var tableContainer = $(document.createElement("div")).attr( "id", - "additional-tables-for-" + this.cid, + `additional-tables-for-${this.cid}`, ); tableContainer.hide(); $(tablesContainer).append(tableContainer); } else if (numTables > 1) - var tableContainer = this.$("#additional-tables-for-" + this.cid); + var tableContainer = this.$(`#additional-tables-for-${this.cid}`); else var tableContainer = tablesContainer; - //Insert the package table HTML + // Insert the package table HTML $(tableContainer).empty(); $(tableContainer).append(tableView.render().el); @@ -1143,39 +1135,39 @@ define([ this.subviews.push(tableView); - //Trigger a custom event in this view that indicates the package table has been rendered + // Trigger a custom event in this view that indicates the package table has been rendered this.trigger("dataPackageRendered"); }, - insertParentLink: function (packageModel) { - var parentPackageMetadata = packageModel.get("parentPackageMetadata"), - view = this; + insertParentLink(packageModel) { + const parentPackageMetadata = packageModel.get("parentPackageMetadata"); + const view = this; - _.each(parentPackageMetadata, function (m, i) { - var title = m.get("title"), - icon = $(document.createElement("i")).addClass( - "icon icon-on-left icon-level-up", - ), - link = $(document.createElement("a")) - .attr( - "href", - MetacatUI.root + "/view/" + encodeURIComponent(m.get("id")), - ) - .addClass("parent-link") - .text("Parent dataset: " + title) - .prepend(icon); + _.each(parentPackageMetadata, (m, i) => { + const title = m.get("title"); + const icon = $(document.createElement("i")).addClass( + "icon icon-on-left icon-level-up", + ); + const link = $(document.createElement("a")) + .attr( + "href", + `${MetacatUI.root}/view/${encodeURIComponent(m.get("id"))}`, + ) + .addClass("parent-link") + .text(`Parent dataset: ${title}`) + .prepend(icon); view.$(view.parentLinkContainer).append(link); }); }, - insertSpatialCoverageMap: function (customCoordinates) { - //Find the geographic region container. Older versions of Metacat (v2.4.3 and less) will not have it classified so look for the header text + insertSpatialCoverageMap(customCoordinates) { + // Find the geographic region container. Older versions of Metacat (v2.4.3 and less) will not have it classified so look for the header text if (!this.$(".geographicCoverage").length) { - //For EML - var title = this.$('h4:contains("Geographic Region")'); + // For EML + let title = this.$('h4:contains("Geographic Region")'); - //For FGDC + // For FGDC if (title.length == 0) { title = this.$('label:contains("Bounding Coordinates")'); } @@ -1188,11 +1180,11 @@ define([ var directions = new Array("north", "south", "east", "west"); } - for (var i = 0; i < georegionEls.length; i++) { + for (let i = 0; i < georegionEls.length; i++) { var georegion = georegionEls[i]; if (typeof customCoordinates !== "undefined") { - //Extract the coordinates + // Extract the coordinates var n = customCoordinates[0]; var s = customCoordinates[1]; var e = customCoordinates[2]; @@ -1200,16 +1192,16 @@ define([ } else { var coordinates = new Array(); - _.each(directions, function (direction) { - //Parse text for older versions of Metacat (v2.4.3 and earlier) + _.each(directions, (direction) => { + // Parse text for older versions of Metacat (v2.4.3 and earlier) if (parseText) { - var labelEl = $(georegion).find( - 'label:contains("' + direction + '")', + const labelEl = $(georegion).find( + `label:contains("${direction}")`, ); if (labelEl.length) { var coordinate = $(labelEl).next().html(); if ( - typeof coordinate != "undefined" && + typeof coordinate !== "undefined" && coordinate.indexOf(" ") > -1 ) coordinate = coordinate.substring( @@ -1219,115 +1211,62 @@ define([ } } else { var coordinate = $(georegion) - .find("." + direction + "BoundingCoordinate") + .find(`.${direction}BoundingCoordinate`) .attr("data-value"); } - //Save our coordinate value + // Save our coordinate value coordinates.push(coordinate); }); - //Extract the coordinates + // Extract the coordinates var n = coordinates[0]; var s = coordinates[1]; var e = coordinates[2]; var w = coordinates[3]; } - //Create Google Map LatLng objects out of our coordinates - var latLngSW = new gmaps.LatLng(s, w); - var latLngNE = new gmaps.LatLng(n, e); - var latLngNW = new gmaps.LatLng(n, w); - var latLngSE = new gmaps.LatLng(s, e); + // Create Google Map LatLng objects out of our coordinates + const latLngSW = new gmaps.LatLng(s, w); + const latLngNE = new gmaps.LatLng(n, e); + const latLngNW = new gmaps.LatLng(n, w); + const latLngSE = new gmaps.LatLng(s, e); - //Get the centertroid location of this data item - var bounds = new gmaps.LatLngBounds(latLngSW, latLngNE); - var latLngCEN = bounds.getCenter(); + // Get the centertroid location of this data item + const bounds = new gmaps.LatLngBounds(latLngSW, latLngNE); + const latLngCEN = bounds.getCenter(); - //If there isn't a center point found, don't draw the map. - if (typeof latLngCEN == "undefined") { + // If there isn't a center point found, don't draw the map. + if (typeof latLngCEN === "undefined") { return; } - //Get the map path color - var pathColor = MetacatUI.appModel.get("datasetMapPathColor"); + // Get the map path color + let pathColor = MetacatUI.appModel.get("datasetMapPathColor"); if (pathColor) { - pathColor = "color:" + pathColor + "|"; + pathColor = `color:${pathColor}|`; } else { pathColor = ""; } - //Get the map path fill color - var fillColor = MetacatUI.appModel.get("datasetMapFillColor"); + // Get the map path fill color + let fillColor = MetacatUI.appModel.get("datasetMapFillColor"); if (fillColor) { - fillColor = "fillcolor:" + fillColor + "|"; + fillColor = `fillcolor:${fillColor}|`; } else { fillColor = ""; } - //Create a google map image - var mapHTML = - ""; - - //Find the spot in the DOM to insert our map image + // Create a google map image + const mapHTML = + ``; + + // Find the spot in the DOM to insert our map image if (parseText) var insertAfter = $(georegion) .find('label:contains("West")') @@ -1335,7 +1274,7 @@ define([ .parent().length ? $(georegion).find('label:contains("West")').parent().parent() : georegion; - //The last coordinate listed + // The last coordinate listed else var insertAfter = georegion; // Get the URL to the interactive Google Maps instance @@ -1345,7 +1284,7 @@ define([ $(insertAfter).append( this.mapTemplate({ map: mapHTML, - url: url, + url, }), ); @@ -1370,7 +1309,7 @@ define([ * @returns {string} The URL to the Google Maps instance. * @since 2.27.0 */ - getGoogleMapsUrl: function (latLngCEN, bounds) { + getGoogleMapsUrl(latLngCEN, bounds) { // Use the window width and height as a proxy for the map dimensions const mapDim = { height: $(window).height(), @@ -1387,50 +1326,60 @@ define([ * Returns the zoom level that will display the given bounding box at * the given dimensions. * @param {LatLngBounds} bounds - The bounding box to display. - * @param {Object} mapDim - The dimensions of the map. + * @param {object} mapDim - The dimensions of the map. * @param {number} mapDim.height - The height of the map. * @param {number} mapDim.width - The width of the map. * @returns {number} The zoom level. * @since 2.27.0 */ - getBoundsZoomLevel: function (bounds, mapDim) { - var WORLD_DIM = { height: 256, width: 256 }; - var ZOOM_MAX = 15; + getBoundsZoomLevel(bounds, mapDim) { + const WORLD_DIM = { height: 256, width: 256 }; + const ZOOM_MAX = 15; // 21 is actual max, but any closer and the map is too zoomed in to be // useful + /** + * + * @param lat + */ function latRad(lat) { - var sin = Math.sin((lat * Math.PI) / 180); - var radX2 = Math.log((1 + sin) / (1 - sin)) / 2; + const sin = Math.sin((lat * Math.PI) / 180); + const radX2 = Math.log((1 + sin) / (1 - sin)) / 2; return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2; } + /** + * + * @param mapPx + * @param worldPx + * @param fraction + */ function zoom(mapPx, worldPx, fraction) { return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2); } - var ne = bounds.getNorthEast(); - var sw = bounds.getSouthWest(); + const ne = bounds.getNorthEast(); + const sw = bounds.getSouthWest(); - var latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI; + const latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI; - var lngDiff = ne.lng() - sw.lng(); - var lngFraction = (lngDiff < 0 ? lngDiff + 360 : lngDiff) / 360; + const lngDiff = ne.lng() - sw.lng(); + const lngFraction = (lngDiff < 0 ? lngDiff + 360 : lngDiff) / 360; - var latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction); - var lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction); + const latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction); + const lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction); return Math.min(latZoom, lngZoom, ZOOM_MAX); }, - insertCitation: function () { + insertCitation() { if (!this.model) return false; - //Create a citation header element from the model attributes - var header = new CitationHeaderView({ model: this.model }); + // Create a citation header element from the model attributes + const header = new CitationHeaderView({ model: this.model }); this.$(this.citationContainer).html(header.render().el); }, - insertDataSource: function () { + insertDataSource() { if ( !this.model || !MetacatUI.nodeModel || @@ -1439,12 +1388,12 @@ define([ ) return; - var dataSource = MetacatUI.nodeModel.getMember(this.model), - replicaMNs = MetacatUI.nodeModel.getMembers( - this.model.get("replicaMN"), - ); + const dataSource = MetacatUI.nodeModel.getMember(this.model); + let replicaMNs = MetacatUI.nodeModel.getMembers( + this.model.get("replicaMN"), + ); - //Filter out the data source from the replica nodes + // Filter out the data source from the replica nodes if (Array.isArray(replicaMNs) && replicaMNs.length) { replicaMNs = _.without(replicaMNs, dataSource); } @@ -1452,20 +1401,20 @@ define([ if (dataSource && dataSource.logo) { this.$("img.data-source").remove(); - //Construct a URL to the profile of this repository - var profileURL = + // Construct a URL to the profile of this repository + const profileURL = dataSource.identifier == MetacatUI.appModel.get("nodeId") - ? MetacatUI.root + "/profile" - : MetacatUI.appModel.get("dataoneSearchUrl") + - "/portals/" + - dataSource.shortIdentifier; + ? `${MetacatUI.root}/profile` + : `${MetacatUI.appModel.get("dataoneSearchUrl")}/portals/${ + dataSource.shortIdentifier + }`; - //Insert the data source template + // Insert the data source template this.$(this.dataSourceContainer) .html( this.dataSourceTemplate({ node: dataSource, - profileURL: profileURL, + profileURL, }), ) .addClass("has-data-source"); @@ -1477,25 +1426,19 @@ define([ .popover({ trigger: "manual", html: true, - title: "From the " + dataSource.name + " repository", - content: function () { - var content = "

" + dataSource.description + "

"; + title: `From the ${dataSource.name} repository`, + content() { + let content = `

${dataSource.description}

`; if (replicaMNs.length) { - content += - "
Exact copies hosted by " + - replicaMNs.length + - ' repositories: