DSpace / dspace-angular

DSpace User Interface built on Angular.io
https://wiki.lyrasis.org/display/DSDOC8x/
BSD 3-Clause "New" or "Revised" License
128 stars 422 forks source link

Display Altmetric badges on simple item view #2400

Open alanorth opened 1 year ago

alanorth commented 1 year ago

Is your feature request related to a problem? Please describe. In earlier versions of DSpace we had the ability to display Altmetric badges on item views based on an item's DOI or Handle (the dspace/config/modules/altmetrics.cfg configuration still exists in the DSpace 7 backend, though it is is not working).

Describe the solution you'd like The ability to display Altmetric donuts on an item view based on the item's metadata. If the item has a DOI then it should be checked first, followed by the Handle. There are API endpoints for both types of identifiers, which return SVG images. In previous versions it was possible to configure the appearance of the badge (size, popup location, etc).

For example, see this DSpace 6 repository with both Altmetric and Dimensions badges:

Screenshot 2023-07-26 at 19-46-38 Planetary boundaries Guiding human development on a changing planet-fs8

(Bonus points for the closely related Dimensions.ai badge).

alanorth commented 1 year ago

I've done a rudimentary implementation of this in a field component:

src/app/item-page/simple/field-components/specific-field/altmetric/item-page-altmetric-field.component.ts ```typescript import { Component, Input, AfterViewInit } from '@angular/core'; import { Item } from '../../../../../core/shared/item.model'; import { ItemPageFieldComponent } from '../item-page-field.component'; @Component({ selector: 'ds-item-page-altmetric-field', templateUrl: './item-page-altmetric-field.component.html' }) /** * This component renders an Altmetric badge. * It expects 1 parameter: The item */ export class ItemPageAltmetricFieldComponent extends ItemPageFieldComponent implements AfterViewInit { // Is this hacky? It feels hacky. I can't figure out any other way to load the // Altmetric embed.js *after* Angular finishes rendering the DOM. ngAfterViewInit() { // Altmetric embed.js import('./embed.js'); } /** * The item to display metadata for */ @Input() item: Item; /** * Helper function to extract the DOI itself from a URI. Should return the * DOI component for any variation of http, https, dx.doi.org, and doi.org. * @type {string} */ parseDoi(doi: string) { const regex = /https?:\/\/(dx\.)?doi\.org\//gi; return doi.replace(regex, ''); } /** * Helper function to extract the Handle itself from a URI. * @type {string} */ parseHandle(handle: string) { const regex = /https?:\/\/hdl\.handle\.net\//gi; return handle.replace(regex, ''); } } ```
src/app/item-page/simple/field-components/specific-field/altmetric/item-page-altmetric-field.component.html ```
```

It works, but I am importing a static version of the Altmetric embed.js from the component. The component uses ngAfterViewInit to import the JavaScript after the div containing the DOI or Handle has been added to the DOM. A better implementation on par with DSpace 6 is welcome!

The result in our DSpace 7.6.1 repository is:

Screenshot

sergius02 commented 1 year ago

I'm trying this but it seems doesn't fully work for me. When i access to a publication with DOI the badge appears, but if i go back to the collection (or navigate to other page) and return, the badge disappear. I need to full refresh the page with F5 to get it back.

alanorth commented 1 year ago

@sergius02 yes I've seen the same. I think it's because this method imports the Altmetric JavaScript and writes to the DOM after Angular has finished loading and saving the cached version of the page. When you navigate away from the page and back, the browser shows the cached version.

We need a more Angular-friendly solution eventually. Hopefully @arvoConsultores can think of something!

sergius02 commented 1 year ago

It seems that calling the funtion _altmetric_embed_init after the import('./embed.js') reload the badge.

  ngAfterViewInit() {
    // Altmetric embed.js
    import('./embed.js');
    window['_altmetric_embed_init']();
  }

This is not a clean way but at least it works.

We need a more Angular-friendly solution eventually. Hopefully @arvoConsultores can think of something!

Yes we need something more angular-like solution, i'm the dev assigned to this from @arvoConsultores 😄, thanks for the code!

alanorth commented 1 year ago

You're welcome, @sergius02. I am new to Angular so this was the best I could come up with. I thought I would share to help other people come up with something better! :smile:

Another thing that will be an issue is using a static import of embed.js. If Altmetric changes their script then we will be using the old one, which could create problems in the future.