import React from "react" ; import { Link } from "react-router-dom" ; import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button" ; import "./PublicationSearchResult.css" ; import { PublicationSearchResult2 } from "./PublicationSearchResult2.js" ; import { PreviewableImage } from "./PreviewableImage.js" ; import { PUBLICATION_EXCESS_ARTICLE_THRESHOLD } from "./constants.js" ; import { gAppRef } from "./App.js" ; import { makeCollapsibleList, pluralString, applyUpdatedVals, removeSpecialFields, isLink } from "./utils.js" ; const axios = require( "axios" ) ; // -------------------------------------------------------------------- export class PublicationSearchResult extends React.Component { render() { // prepare the basic details const display_description = PreviewableImage.adjustHtmlForPreviewableImages( this.props.data[ "pub_description!" ] || this.props.data.pub_description ) ; const publ = gAppRef.caches.publishers[ this.props.data.publ_id ] ; const image_url = PublicationSearchResult.makeImageUrl( this.props.data ) ; // prepare the publication's URL let pub_url = this.props.data.pub_url ; if ( pub_url && ! isLink(pub_url) ) pub_url = gAppRef.makeExternalDocUrl( pub_url ) ; // prepare the tags let tags = [] ; if ( this.props.data[ "tags!" ] ) { // the backend has provided us with a list of tags (possibly highlighted) - use them directly // NOTE: We don't normally show HTML in tags, but in this case we need to, in order to be able to highlight // matching search terms. This will have the side-effect of rendering any HTML that may be in the tag, // but we can live with that. for ( let i=0 ; i < this.props.data["tags!"].length ; ++i ) { const tag = this.props.data.pub_tags[ i ] ; // nb: this is the actual tag (without highlights) tags.push( ) ; } } else { if ( this.props.data.pub_tags ) { this.props.data.pub_tags.map( tag => tags.push( {tag} ) ) ; } } // prepare the articles let articles = [] ; if ( this.props.data.articles ) { for ( let i=0 ; i < this.props.data.articles.length ; ++i ) { const article = this.props.data.articles[ i ] ; if ( this.props.onArticleClick ) { // forward clicks on the article to the parent articles.push(
this.props.onArticleClick( article.article_id ) } style = {{ cursor: "pointer" }} title = "Go to this article." /> ) ; } else { // handle clicks on the article normally articles.push( ) ; } } } // prepare the menu const menu = ( this.onEditPublication() } > Edit. Edit this.onDeletePublication() } > Delete. Delete ) ; return (
gAppRef.setTestAttribute( r, "pub_id", this.props.data.pub_id ) } >
{menu} { publ && } { pub_url && Open publication. }
{ image_url && }
{ makeCollapsibleList( "Articles", articles, PUBLICATION_EXCESS_ARTICLE_THRESHOLD, {float:"left",marginBottom:"0.25em"} ) }
{ this.props.data.pub_date &&
{this.props.data.pub_date}
} { tags.length > 0 &&
{tags}
}
) ; } componentDidMount() { PreviewableImage.activatePreviewableImages( this ) ; } static onNewPublication( notify ) { PublicationSearchResult2._doEditPublication( {}, null, (newVals,refs) => { axios.post( gAppRef.makeFlaskUrl( "/publication/create", {list:1} ), newVals ) .then( resp => { // update the caches gAppRef.caches.publications = resp.data.publications ; gAppRef.caches.tags = resp.data.tags ; // unload any updated values applyUpdatedVals( newVals, newVals, resp.data.updated, refs ) ; // update the UI with the new details notify( resp.data.pub_id, newVals ) ; if ( resp.data.warnings ) gAppRef.showWarnings( "The new publication was created OK.", resp.data.warnings ) ; else gAppRef.showInfoToast(
The new publication was created OK.
) ; gAppRef.closeModalForm() ; // NOTE: The parent publisher will update itself in the UI to show this new publication, // since we've just received an updated copy of the publications. } ) .catch( err => { gAppRef.showErrorMsg(
Couldn't create the publication:
{err.toString()}
) ; } ) ; } ) ; } onEditPublication() { // get the articles for this publication let articles = this.props.data.articles ; // nb: _doEditPublication() might change the order of this list PublicationSearchResult2._doEditPublication( this.props.data, articles, (newVals,refs) => { // send the updated details to the server newVals.pub_id = this.props.data.pub_id ; if ( articles ) newVals.article_order = articles.map( a => a.article_id ) ; axios.post( gAppRef.makeFlaskUrl( "/publication/update", {list:1} ), newVals ) .then( resp => { // update the caches gAppRef.caches.publications = resp.data.publications ; gAppRef.caches.tags = resp.data.tags ; // update the UI with the new details applyUpdatedVals( this.props.data, newVals, resp.data.updated, refs ) ; removeSpecialFields( this.props.data ) ; if ( newVals.imageData ) gAppRef.forceFlaskImageReload( "publication", newVals.pub_id ) ; this.forceUpdate() ; PreviewableImage.activatePreviewableImages( this ) ; if ( resp.data.warnings ) gAppRef.showWarnings( "The publication was updated OK.", resp.data.warnings ) ; else gAppRef.showInfoToast(
The publication was updated OK.
) ; gAppRef.closeModalForm() ; // NOTE: The parent publisher will update itself in the UI to show this updated publication, // since we've just received an updated copy of the publications. } ) .catch( err => { gAppRef.showErrorMsg(
Couldn't update the publication:
{err.toString()}
) ; } ) ; } ) ; } onDeletePublication() { let doDelete = ( nArticles ) => { // confirm the operation let warning ; if ( typeof nArticles === "number" ) { if ( nArticles === 0 ) warning =
No articles will be deleted.
; else warning =
{ pluralString(nArticles,"associated article") + " will also be deleted." }
; } else { warning = (
Error. WARNING: Couldn't check if any associated articles will be deleted:
{nArticles.toString()}
) ; } const content = (
Delete this publication?
{warning}
) ; gAppRef.ask( content, "ask", { "OK": () => { // delete the publication on the server axios.get( gAppRef.makeFlaskUrl( "/publication/delete/" + this.props.data.pub_id, {list:1} ) ) .then( resp => { // update the caches gAppRef.caches.publications = resp.data.publications ; gAppRef.caches.tags = resp.data.tags ; // update the UI this.props.onDelete( "pub_id", this.props.data.pub_id ) ; resp.data.deleteArticles.forEach( article_id => { this.props.onDelete( "article_id", article_id ) ; } ) ; if ( resp.data.warnings ) gAppRef.showWarnings( "The publication was deleted.", resp.data.warnings ) ; else gAppRef.showInfoToast(
The publication was deleted.
) ; } ) .catch( err => { gAppRef.showErrorToast(
Couldn't delete the publication:
{err.toString()}
) ; } ) ; }, "Cancel": null, } ) ; } // get the publication details axios.get( gAppRef.makeFlaskUrl( "/publication/" + this.props.data.pub_id ) ) .then( resp => { doDelete( resp.data.nArticles ) ; } ) .catch( err => { doDelete( err ) ; } ) ; } static makeDisplayName( vals, allowAlternateContent ) { let pub_name = null ; if ( allowAlternateContent && vals["pub_name!"] ) pub_name = vals[ "pub_name!" ] ; if ( ! pub_name ) pub_name = vals.pub_name ; if ( vals.pub_edition ) return pub_name + " (" + vals.pub_edition + ")" ; else return pub_name ; } _makeDisplayName( allowAlternateContent ) { return PublicationSearchResult.makeDisplayName( this.props.data, allowAlternateContent ) ; } static makeImageUrl( vals ) { let image_url = gAppRef.makeFlaskImageUrl( "publication", vals.pub_image_id ) ; if ( ! image_url ) { // check if the parent publisher has an image if ( vals.publ_id ) { const publ = gAppRef.caches.publishers[ vals.publ_id ] ; if ( publ ) image_url = gAppRef.makeFlaskImageUrl( "publisher", publ.publ_image_id ) ; } } return image_url ; } }