-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsearchDOIs.jsx
511 lines (429 loc) · 23.6 KB
/
searchDOIs.jsx
1
// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————// ## searchDOIs.jsx | Auteur : Emmanuel Côtez ([email protected]/[email protected]) | https://github.com/ecotez-mnhn ##// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————//// Version : 1.04//// Works with Adobe InDesign CC//// ———————————————————————————————————————————————————————————————————————————————————————————————//// [FR]// Script d'ajout automatique des DOI aux entrées de la bibliographie via l'API fournie par CrossREF.//// – Le programme nécessite de sélection un style de paragraphe (Journaux du Muséum, EJT, Mémoires du Muséum ou "Other") et analyse ensuite le contenu de chaque entrée de bibliographie (qui doit être dans un unique paragraphe), en extrait les données et les envoie à CrossREF pour récupérer le DOI correspondant, s'il existe.// – Les DOIs ajoutés sont automatiquement liés et stylés en style "Lien hypertexte" ; si un DOI existe déjà, le lien existant est supprimé et recréé ;// – Les entrées bibliographiques non trouvées apparaissent soulignées en vert, et celles dont les données n'ont pas pu être extraites soulignées en rouge ;// – Les couleurs et le style de caractère sont automatiquement créés s'ils n'existent pas ;// – L'entrée "Other" permet de sélectionner un style de paragraphe personnalisé pour les références ; les expressions régulières permettant d'extraire les données sont configurables ci-dessous.// // Dépendances :// collator.jsxinc// extendables/extendables.jsx// getURLs.jsx// functionsEc.js// ———————————————————————————————————————————————————————————————————————————————————————————————//// [EN]// Script for automatically adding DOIs to bibliography entries via the API provided by CrossREF.//// The program requires you to select a paragraph style (Journals of the Museum, EJT, Memoirs of the Museum or Other) and then analyses the content of each bibliography entry (which must be in a single paragraph), extract the data and send them to CrossREF and get back the DOI if exists.// - DOIs added are automatically linked and styled in "Lien hypertexte" character style; if a DOI already exists, the existing link is deleted and recreated;// - Bibliographic entries not found appear underlined in green, and those from which data could not be extracted underlined in red;// - Colours and character style are automatically created if they do not exist;// - The "Other" entry allows the selection of a personalised paragraph style for the references; regular expressions allowing the data to be extracted can be configured below.//// Dependencies:// collator.jsxinc// extendables/extendables.jsx// getURLs.jsx// functionsEc.js// ———————————————————————————————————————————————————————————————————————————————————————————————//// ###################################################################################################// ###################################################################################################// Configuration of the GREP expressions used to find data in bibliographic entries for choice "Other"// ---------------------------------------------------------------------------------------------------var otherRegexFirstAuthor = "(\\u[\\l-]+\\s?)+" ;var otherRegexYear = "\\d{4}(?=\\.\\s—)" ;var otherRegexJournalTitle = "[\\u\\l\\s(),-]+(?=\\s\\d+(\\s\\(\\d+\\))?:)" ;var otherRegexVolume = "\\d+(?=(\\s?\\(((\\d+-?(\\d+)?)|([a-z\\.]+))\\))?:)" ;var otherRegexFirstPage = "(?<=:\\s)\\d+" ;var otherRegexTitle = "(?<=—\\s).*?(?=((\\.\\s)|(,\\sin)))" ;// ---------------------------------------------------------------------------------------------------// Reference format example (corresponds to the Museum of Paris journals bibliography format):// ---------------------------------------------------------------------------------------------------// Beck R. M. D., Voss R. S. & Jansa S. A. 2022. — Craniodental morphology and Phylogeny of marsupials. Bulletin of the American Museum of Natural History 457: 1-350.// ---------------------------------------------------------------------------------------------------// otherRegexFirstAuthor = "Beck"// otherRegexYear = "2022"// otherRegexJournalTitle = "Bulletin of the American Museum of Natural History"// otherRegexVolume = "457"// otherRegexFirstPage = "1"// otherRegexTitle = "Craniodental morphology and Phylogeny of marsupials"// ---------------------------------------------------------------------------------------------------// ###################################################################################################// ###################################################################################################// Mise à jour automatique de l'affichage au cours du déroulement du scriptapp.scriptPreferences.enableRedraw = true;// Fonctions ##################################### function GetAppVersionName() { // function written by Kasyan Servetsky (http://kasyan.ho.ua/snippets/get_application_version_function.html) var appPath = app.filePath.fsName, tempArr = (File.fs == "Windows") ? appPath.split("\\") : appPath.split("/"), appName = tempArr[tempArr.length - 1].replace(/^Adobe InDesign\s/, "").replace(/\s\(32-bit\)/, "").replace(/\s+/, " "); return appName; } function char_style_exist(style_name) { if(app.activeDocument.characterStyles.item (style_name) == null) { app.activeDocument.characterStyles.add({name:style_name}); } return app.activeDocument.characterStyles.item(style_name); } function generate() { return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); }// Fin des fonctions ##############################// Inclusions ##################################### #include 'collator.jsxinc'; #include 'extendables/extendables.jsx'; #include 'getURLs.jsx'; #include 'functionsEc.js'; // Fin des inclusions ############################# // Début du script ################################ myDocument = app.documents.item(0); var countDoi=0; var countBhlid=0; var countGallicaID=0; // Création du style "Lien hypertexte" s'il n'existe pas myStyle = char_style_exist("Lien hypertexte") ; // Création et/ou sélection de la couleur en fonction de la version d'INDD if (GetAppVersionName()=="CS6") { // pour CS6 myColorToCheck = app.activeDocument.colors.itemByName("Lien hypertexte"); if(myColorToCheck.isValid) { myStyle.fillColor = "Lien hypertexte" ; } else { alert ("Avertissement : la couleur nommée \"Lien hypertexte\" n'existe pas ; un style de caractères sera appliqué aux liens ajoutés, mais ils ne seront pas colorés.") ; } } else { // pour autres (donc CC) myColorAdd(app.activeDocument, "Lien hypertexte", ColorModel.PROCESS, [100,75,0,0]); // bleu CMJN myStyle.fillColor = "Lien hypertexte" ; myColorAdd(app.activeDocument, "references_rouge", ColorModel.PROCESS, [0,100,100,0]); // rouge Références myColorAdd(app.activeDocument, "references_vert", ColorModel.PROCESS, [100,25,100,0]); // vert Références } // Selection of the reference style ("EJT", "Journaux Muséum", "Mémoires du Muséum" or "Other") var w, layout; layout = "dialog { dropdown: DropDownList { size: [20,20] properties: { items: ['EJT','Journaux Muséum','Mémoires du Muséum','Other'] } } }"; w = new Window(layout); w.dropdown.selection=1; w.dropdown.minimumSize.width = 300; w.dropdown.minimumSize.height = 38; w.dropdown.title = "Reference paragraph style:"; w.add ("button", undefined, "OK"); w.show(); styleRef = w.dropdown.selection.text ; // End of the selection of the reference style var ProgressBar = function(/*str*/title) { var w = new Window('palette', ' '+title, {x:0, y:0, width:350, height:350}); panel1 = w.add('panel', [10,10,340,80], 'Search progress...', {borderStyle:'gray'}); st = panel1.add('statictext', {x:10, y:36, width:300, height:120}, '', {multiline:true}); pb = panel1.add('progressbar', {x:20, y:12, width:300, height:12}, 0, 100); panel2 = w.add('panel', [10,90,340,190], 'Reference being processed', {borderStyle:'gray'}); st2 = panel2.add('statictext', {x:10, y:10, width:300, height:140}, '', {multiline:true}); panel3 = w.add('panel', [10,200,340,340], 'Data actually extracted', {borderStyle:'gray'}); st3 = panel3.add('statictext', {x:10, y:10, width:300, height:220}, '', {multiline:true}); st.justify = 'center'; st3.justify = 'left' ; st2.justify = 'center'; st3.text = "" ; st3.graphics.font = ScriptUI.newFont ("Helvetica", "", 12); st2.graphics.font = ScriptUI.newFont ("Helvetica", "", 12); w.center(); this.reset = function(msg,maxValue) { st.text = msg; pb.value = 0; pb.maxvalue = maxValue||0; pb.visible = !!maxValue; w.show(); }; this.changeTxt = function(msg) { st.text = msg; w.show(); }; this.changeTxt2 = function(msg2) { st2.text = msg2; w.show(); }; this.changeTxt3 = function(msg3) { st3.text = msg3; w.show(); }; this.hit = function() {++pb.value;}; this.hide = function() {w.hide();}; this.close = function() {w.close();}; }; // __________________________________________________// Fenêtre de sélection d'un style de paragraphe si "Other" sélectionné dans la fenêtre précédente if (styleRef=="Other") { myDoc = app.activeDocument; myStyles = myDoc.paragraphStyles; myStringList = myStyles.everyItem().name; var myDialog = app.dialogs.add({name:"Select the 'Reference' paragraph style:"}) with(myDialog){ with(dialogColumns.add()){ with (dialogRows.add()) { with (dialogColumns.add()) { staticTexts.add({staticLabel:"Paragraph style:"}); } with (dialogColumns.add()) { myStyle = dropdowns.add({stringList:myStringList,selectedIndex:0,minWidth:133}); } } } } var myResult = myDialog.show(); if (myResult != true){ // user clicked Cancel myDialog.destroy(); errorExit(); } theStyle = myStyle.selectedIndex; theStyle = myStyles[theStyle] ; myDialog.destroy(); }// fin de la fenêtre de sélection d'un style...// __________________________________________________ // Extraction des références de la bibliographie app.findGrepPreferences=app.changeGrepPreferences=null; if (styleRef=="EJT") { app.findGrepPreferences.appliedParagraphStyle = "References" ; } if (styleRef=="Journaux Muséum") { app.findGrepPreferences.appliedParagraphStyle = "Références"; } if (styleRef=="Mémoires du Muséum") { app.findGrepPreferences.appliedParagraphStyle = "bibliographie"; } if (styleRef=="Other") { app.findGrepPreferences.appliedParagraphStyle = theStyle; } app.changeGrepPreferences.changeTo="$0" ; app.findGrepPreferences.findWhat=".+(?=\\r)"; if (app.selection[0] == null || app.selection[0].contents.length == 0) { applyTo=true; } else { applyTo=false; } if (applyTo==true) { refFromBiblio = app.activeDocument.findGrep() ; } else { refFromBiblio = app.selection[0].findGrep(); } var numRef=0 ; var numRefNonTrouvees=0 ; var listAuteurs=new Array(); var listAnnees=new Array(); var listTitres=new Array(); var listJournaux=new Array(); var listVolumes=new Array(); var listPages=new Array(); var refNonTrouvee=new Array(); var trouve=new Array(); // Traitement des références extraites et extraction des données var j=0; var pBar = new ProgressBar("Searching DOIs"); pBar.reset(refFromBiblio.length+" reference(s) to check", refFromBiblio.length); while (j<refFromBiblio.length) { refFromBiblio[j].showText(); refFromBiblio[j].select(); // Extraction du nom du premier auteur app.findGrepPreferences=app.changeGrepPreferences=null; if (styleRef=="EJT") { app.findGrepPreferences.findWhat="(\\u[\\l-]+\\s?)+"; } if (styleRef=="Journaux Muséum") { app.findGrepPreferences.findWhat="(\\u[\\l-]+\\s?)+"; } if (styleRef=="Mémoires du Muséum") { app.findGrepPreferences.findWhat="(\\u[\\u-]+\\s?)+"; } if (styleRef=="Other") { app.findGrepPreferences.findWhat = otherRegexFirstAuthor ; } auteur = app.selection[0].findGrep() ; if (auteur.length != 0) { try { listAuteurs[j] = auteur[0].contents.toString() ; } catch (e) {} } // fin de l'extraction du nom du premier auteur // Extraction de l'année app.findGrepPreferences=app.changeGrepPreferences=null; if (styleRef=="EJT") { app.findGrepPreferences.findWhat="\\d{4}(?=\\.\\s—)"; } if (styleRef=="Journaux Muséum") { app.findGrepPreferences.findWhat="\\d{4}(?=\\.\\s—)"; } if (styleRef=="Mémoires du Muséum") { app.findGrepPreferences.findWhat="\\d{4}(?=\\s—)"; } if (styleRef=="Other") { app.findGrepPreferences.findWhat = otherRegexYear ; } annee = app.selection[0].findGrep() ; if (annee.length != 0) { try { listAnnees[j] = annee[0].contents.toString() ; } catch (e) {} } // fin de l'extraction de l'année // Extraction du titre du journal app.findGrepPreferences=app.changeGrepPreferences=null; if (styleRef=="EJT") { app.findGrepPreferences.findWhat="[\\u\\l\\s(),-]+(?=\\s\\d+(\\s\\(\\d+\\))?:)"; } if (styleRef=="Journaux Muséum") { app.findGrepPreferences.findWhat="[\\u\\l\\s(),-]+(?=\\s\\d+(\\s\\(\\d+\\))?:)"; } if (styleRef=="Mémoires du Muséum") { app.findGrepPreferences.findWhat="[\\u\\l\\s(),'-]+(?=\\s\\d+(\\s?\\(\\d+\\))?:)"; } if (styleRef=="Other") { app.findGrepPreferences.findWhat = otherRegexJournalTitle ; } titreJournal = app.selection[0].findGrep() ; if (titreJournal.length != 0) { try { listJournaux[j] = titreJournal[0].contents.toString() ; } catch (e) {} } // fin de l'extraction du titre du journal // Volume (fascicule optionnel) app.findGrepPreferences=app.changeGrepPreferences=null; if (styleRef=="EJT" || styleRef=="Journaux Muséum" || styleRef=="Mémoires du Muséum") { app.findGrepPreferences.findWhat="\\d+(?=(\\s?\\(((\\d+-?(\\d+)?)|([a-z\\.]+))\\))?:)"; } if (styleRef=="Other") { app.findGrepPreferences.findWhat = otherRegexVolume ; } volume = app.selection[0].findGrep() ; if (volume.length != 0) { try { listVolumes[j] = volume[0].contents.toString() ; } catch (e) {} } // fin volume // Première page (i la requête mais le 'match' est optionnel app.findGrepPreferences=app.changeGrepPreferences=null; if (styleRef=="EJT" || styleRef=="Journaux Muséum" || styleRef=="Mémoires du Muséum") { app.findGrepPreferences.findWhat="(?<=:\\s)\\d+"; } if (styleRef=="Other") { app.findGrepPreferences.findWhat = otherRegexFirstPage ; } firstpage = app.selection[0].findGrep() ; if (firstpage.length != 0) { try { listPages[j] = firstpage[0].contents.toString() ; } catch (e) {} } // fin première page // Extraction du titre de l'article ou du livre app.findGrepPreferences=app.changeGrepPreferences=null; if (styleRef=="EJT") { app.findGrepPreferences.findWhat="(?<=\\d{4}\\.\\s).*?(?=((\\.\\s)|(,\\sin)))"; // EJT } else if (styleRef=="Journaux Muséum") { app.findGrepPreferences.findWhat="(?<=—\\s).*?(?=((\\.\\s)|(,\\sin)))"; } else if (styleRef=="Mémoires du Muséum") { app.findGrepPreferences.findWhat="(?<=\\d{4}\\s—\\s).*?(?=((\\.\\s)|(,\\sin)))"; } else if (styleRef=="Other") { app.findGrepPreferences.findWhat=otherRegexTitle; } titreArticle = app.selection[0].findGrep() ; if (titreArticle.length != 0) { try { listTitres[j] = titreArticle[0].contents.toString() ; } catch (e) {} } // fin de l'extraction du titre de l'article ou du livre // fin du traitement des références extraites et de l'extraction des données // Affichage nbRef = j ; nbRef++; var trouveDOI=false; var trouveBhl=false; var trouveGallica=false; if (nbRef==1) { wStr = nbRef + " reference processed on " + refFromBiblio.length ; } else { wStr = nbRef + " references processed on " + refFromBiblio.length + " - "+countDoi+" DOI found" ; } pBar.changeTxt(wStr, refFromBiblio.length); refTrait = refFromBiblio[j].contents ; refTrait3 = "First author: " + listAuteurs[j] + "\nTitle: " + listTitres[j] + "\nYear: " + listAnnees[j] + "\nJournals name: " + listJournaux[j] + "\nVolume: " + listVolumes[j] ; pBar.changeTxt2(refTrait); pBar.changeTxt3(refTrait3); var response = ""; // fin de l'affichage // Recherche du DOI sur CrossREF ###################################################################### count=0; if (listAuteurs[j]&&listJournaux[j]&&listVolumes[j]) { // si c'est un article var requeteTxt = encodeURI("https://doi.crossref.org/openurl?pid=mnhn:mnhn818&aulast="+listAuteurs[j]+"&title="+listJournaux[j]+"&volume="+listVolumes[j]+"&date="+listAnnees[j]+"&spage="+listPages[j]+"&redirect=false") ; var http = require("http"); var response = http.get(requeteTxt); if (response.body.search('<doi type="journal_article">') == -1) { } else { var res = response.body.split('<doi type="journal_article">') ; res = res[1].split('</doi>') ; var doi = res[0] ; var url = "https://doi.org/"+doi ; // test de la présence d'une URL à la fin de la référence app.findGrepPreferences=app.changeGrepPreferences=null; app.findGrepPreferences.findWhat = "http.+" ; testLink = app.selection[0].findGrep() ; if (testLink[0] == undefined) { // si l'entrée de bibliographie ne contient pas d'URL if (refFromBiblio[j].contents.toString().charAt(refFromBiblio[j].contents.length-1)==" ") { refFromBiblio[j].contents = refFromBiblio[j].contents + url ; } else { refFromBiblio[j].contents = refFromBiblio[j].contents + " " + url ; } } refFromBiblio[j].select(); refFromBiblio[j].showText(); if (testLink[0] != undefined) { remove_link(app.selection[0]); } // suppression du lien uniquement si une URL a été détectée app.findGrepPreferences=app.changeGrepPreferences=null; app.findGrepPreferences.findWhat = "http.+" ; tabLink = app.selection[0].findGrep() ; if (tabLink[0] != undefined) { myLink = tabLink[0].contents ; var name = tabLink[0].texts[0].contents ; var MyLinkName = "DOI_"+myLink+"_"+generate() ; try { var myHyperlinkURLDestination = app.activeDocument.hyperlinkURLDestinations.add(myLink) ; } catch (e) { myHyperlinkURLDestination = myDoc.hyperlinkURLDestinations.itemByName(myLink); if (myHyperlinkURLDestination == undefined) { alert("problème avec une HyperDestination: " + liens[i].contents + "\nSupprimer la destination via le panneau HyperLines/Options de cible d'hyperlien"); } } try { var myHyperlinkSource = app.activeDocument.hyperlinkTextSources.add(tabLink[0].texts[0]) ; var myHyperlink = app.activeDocument.hyperlinks.add(myHyperlinkSource, myHyperlinkURLDestination, {name: MyLinkName+(count)}) ; } catch (e) {} } refFromBiblio[j].select(); app.findGrepPreferences=app.changeGrepPreferences = null ; app.changeGrepPreferences.appliedCharacterStyle = "Lien hypertexte" ; app.findGrepPreferences.findWhat = "http.+" ; app.selection[0].changeGrep() ; countDoi++; count++; trouveDOI=true; } // Fin de la recherche du DOI sur CrossREF ###################################################################### } // Fin du if (listAuteurs[j]&&listJournaux[j]&&listVolumes[j]) // Soulignement des lignes non trouvées ###################################################################### if (trouveDOI==false) { // Si aucun résultat n'a été trouvé, renseigner un tableau des références à chercher manuellement ; refNonTrouvee[j] = refFromBiblio[j].contents.toString() ; refFromBiblio[j].underline=true; refFromBiblio[j].underlineWeight=1; // à corriger pour prendre en compte la création des couleurs correspondantes if (listVolumes[j]!=undefined && listJournaux[j]!=undefined && listTitres[j]!=undefined && listAuteurs[j]!=undefined) { refFromBiblio[j].underlineColor = myDocument.swatches.item("references_vert") ; // OK } else { refFromBiblio[j].underlineColor = myDocument.swatches.item("references_rouge") ; // OK } numRefNonTrouvees++; } // fin du soulignement des lignes non trouvées ############################################################### // fin du traitement, référence suivante pBar.hit(); j++; } pBar.close(); alert (countDoi + " DOI have been added to references.\n"+numRefNonTrouvees+" references without ID (articles without DOI underlined in green, references not found in red)") ;