Skip to content

Commit

Permalink
Show alert box on duplicate dataset on landing pg
Browse files Browse the repository at this point in the history
Remove the Canonical Dataset field in the General section of dataset landing pages, and instead show a more prominent blue info box at the top of the page with the citation.

Issue #2541
  • Loading branch information
robyngit committed Oct 17, 2024
1 parent ded5b86 commit 0587969
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 92 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
162 changes: 71 additions & 91 deletions src/js/views/CanonicalDatasetHandlerView.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,12 @@ define([
// The URI for the prov:wasDerivedFrom annotation
const PROV_WAS_DERIVED_FROM = "http://www.w3.org/ns/prov#wasDerivedFrom";

// What to call the field that links to the original dataset
const CANONICAL_LABEL = "Canonical Dataset";
// The text to display in the info tooltip to explain what the canonical
// dataset field means
const CANONICAL_TOOLTIP_TEXT =
"The original dataset this version was derived from. This dataset is essentially a duplicate of the original.";
// The text to show in the alert box at the top of the MetadataView
const ALERT_TEXT =
"This version of the dataset is a replica or minor variant of the original dataset:";
// The text to display in the info tooltip to explain what the info icon means
const INFO_ICON_TOOLTIP_TEXT =
"This dataset is essentially a duplicate of of another, original dataset.";
"This dataset is replica or minor variant of another, original dataset.";
// In the citation modal, the heading to use for the dataone version citation
const CITATION_TITLE_DATAONE = "This Version of the Dataset";
// In the citation modal, the heading to use for the canonical dataset
Expand All @@ -30,20 +27,23 @@ define([
// The bootstrap icon name to use for the info icon
const INFO_ICON_NAME = "icon-copy";

// Class names used in this view
const CLASS_NAMES = {
alertBox: ["alert", "alert-info", "alert-block"], // TODO: need alert-block?
alertIcon: ["icon", "icon-info-sign", "icon-on-left"],
alertCitation: "canonical-citation",
};

// The following properties are used to identify parts of the MetadataView.
// If the MetadataView changes, these properties may need to be updated.

// The name of the property on the MetadataView that contains subviews
const SUBVIEW_PROP = "subviews";
// The name of the property on the MetadataView that contains the citation
// modal
const CITATION_MODAL_PROP = "citationModal";
// Class names used in the MetadataView that we also need to use in this view
const METADATA_VIEW_CLASS_NAMES = {
fieldItem: "control-group",
fieldLabel: "control-label",
fieldValue: ["controls", "controls-well"],
fieldInfoIcon: ["tooltip-this", "icon", "icon-info-sign"],
const METADATA_VIEW = {
// The selector for the container that contains the info icons and metrics buttons
controlsSelector: "#metadata-controls-container",
// The name of the property on the MetadataView that contains the citation
// modal
citationModalProp: "citationModal",
// The name of the property on the MetadataView that contains subviews
subviewProp: "subviews",
};

/**
Expand Down Expand Up @@ -72,32 +72,6 @@ define([
*/
metdataView: null,

/**
* The value of the label to insert the canonical dataset field before.
* @type {string}
*/
insertFieldBefore: "Identifier",

/**
* Creates a field item for the MetadataView.
* @param {string} label - The label for the field.
* @param {string} value - The value for the field.
* @param {string} tooltipText - The text to display in the info tooltip.
* @param {object} classes - The classes to apply to the field item.
* @returns {string} The HTML for the field item.
*/
fieldItemTemplate(label, value, tooltipText, classes) {
return `<div class="${classes.fieldItem}">
<label class="${classes.fieldLabel}">
${label}
<span style="display: inline-block; width: 1em; text-align: center;">
<i class="${classes.fieldInfoIcon.join(" ")}" data-toggle="tooltip" title="${tooltipText}"></i>
</span>
</label>
<div class="${classes.fieldValue.join(" ")}">${value}</div>
</div>`;
},

/**
* Initialize the CanonicalDatasetHandlerView.
* @param {object} options - A set of options to initialize the view with.
Expand All @@ -120,8 +94,8 @@ define([
this.reset();
const hasCanonical = this.detectCanonicalDataset();
if (!hasCanonical) return this;
this.fieldItem = this.addFieldItem();
this.infoIcon = this.addInfoIcon();
this.alertBox = this.addAlertBox();
this.getCitationInfo();
this.modifyCitationModal();
this.hideAnnotations();
Expand All @@ -133,8 +107,8 @@ define([
* made by this view.
*/
reset() {
this.fieldItem?.remove();
this.infoIcon?.remove();
this.alertBox?.remove();
this.showAnnotations();
this.citationModel.reset();
this.canonicalUri = null;
Expand Down Expand Up @@ -214,7 +188,7 @@ define([
* @returns {AnnotationView[]} An array of AnnotationView instances.
*/
getAnnotationViews() {
return this.metadataView[SUBVIEW_PROP].filter(
return this.metadataView[METADATA_VIEW.subviewProp].filter(
(view) => view?.type === ANNO_VIEW_TYPE,
);
},
Expand Down Expand Up @@ -252,7 +226,7 @@ define([
this.stopListening(this.crossRef);
this.listenToOnce(this.crossRef, "sync", () => {
view.citationModel.setSourceModel(this.crossRef);
view.updateFieldItemWithCitation();
view.updateAlertBox();
});
this.crossRef.fetch();
},
Expand Down Expand Up @@ -293,62 +267,67 @@ define([
},

/**
* Add a row in the MetadataView to display the canonical dataset URI
* @returns {Element} The field item element that was added to the view.
* Adds an alert box to the top of the MetadataView to indicate that the
* dataset being displayed is a replica or minor variant of the original
* dataset.
* @returns {Element} The alert box element that was added to the view.
*/
addFieldItem() {
const { canonicalUri, fieldItemTemplate } = this;
const itemHTML = fieldItemTemplate(
CANONICAL_LABEL,
`<a href="${canonicalUri}">${canonicalUri}</a>`,
CANONICAL_TOOLTIP_TEXT,
METADATA_VIEW_CLASS_NAMES,
addAlertBox() {
const controls = this.metadataView.el.querySelector(
METADATA_VIEW.controlsSelector,
);

// Vivify the item so we can reference it later
const range = document.createRange();
const fragment = range.createContextualFragment(itemHTML);
const item = fragment.firstElementChild;
const alertBox = document.createElement("section");
alertBox.classList.add(...CLASS_NAMES.alertBox);

// Find the parent item that contains the field name the view should
// be inserted before
const labels = Array.from(
this.metadataView.el.querySelectorAll("label"),
);
const insertBeforeLabel = labels.find(
(label) => label.textContent.trim() === this.insertFieldBefore,
);
// Insert the new field item before the label
insertBeforeLabel.parentElement.before(item);
return item;
},
const icon = document.createElement("i");
icon.classList.add(...CLASS_NAMES.alertIcon);

/**
* Replaces the DOI in the field item with a full citation for the
* canonical dataset.
*/
updateFieldItemWithCitation() {
const { citationModel, fieldItem } = this;
if (!fieldItem) return;
const heading = document.createElement("h5");
heading.textContent = ALERT_TEXT;

// Add a div that will contain the citation information
const citeContainer = document.createElement("div");
citeContainer.classList.add(CLASS_NAMES.alertCitation);
// Just add the URI for now
citeContainer.textContent = this.canonicalUri;

heading.prepend(icon);
alertBox.append(heading, citeContainer);

alertBox.style.marginTop = "-1rem";
heading.style.marginTop = "0";
citeContainer.style.marginLeft = "1rem";

this.alertBox = alertBox;

// Insert the citation view before the metadata controls
controls.before(alertBox);

return alertBox;
},

/** Updates the citation information in the alert box. */
updateAlertBox() {
const alertBox = this.alertBox || this.addAlertBox();
const citeContainer = alertBox.querySelector(
`.${CLASS_NAMES.alertCitation}`,
);
const { citationModel } = this;
const citationView = new CitationView({
model: citationModel,
className: "canonical-citation",
// Don't use styles from default class
className: "",
createTitleLink: false,
openLinkInNewTab: true,
}).render();

// Replace the DOI with the citation
const fieldValueEl = fieldItem.querySelector(
`.${METADATA_VIEW_CLASS_NAMES.fieldValue.join(".")}`,
);
fieldValueEl.innerHTML = "";
fieldValueEl.appendChild(citationView.el);
citeContainer.innerHTML = "";
citeContainer.appendChild(citationView.el);
},

/** Open the citation modal. */
openCitationModal() {
this.metadataView[CITATION_MODAL_PROP].show();
this.metadataView[METADATA_VIEW.citationModalProp].show();
},

/**
Expand All @@ -359,7 +338,8 @@ define([
modifyCitationModal() {
const view = this;
// The CitationModalView is recreated each time it is shown.
const citationModalView = this.metadataView[CITATION_MODAL_PROP];
const citationModalView =
this.metadataView[METADATA_VIEW.citationModalProp];
this.listenToOnce(citationModalView, "rendered", () => {
citationModalView.canonicalDatasetMods = true;
// Add heading for each citation
Expand Down
2 changes: 1 addition & 1 deletion src/js/views/MetadataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ define([
// If we re-render before the first render is complete the view breaks
this.stopListening(this, "renderComplete", this.render);
this.listenToOnce(this, "renderComplete", this.render);
return;
return this;
}
this.isRendering = true;
this.stopListening();
Expand Down

0 comments on commit 0587969

Please sign in to comment.