diff --git a/landingPages/result/resultLanding.component.ts b/landingPages/result/resultLanding.component.ts index 400184b8..f9191771 100644 --- a/landingPages/result/resultLanding.component.ts +++ b/landingPages/result/resultLanding.component.ts @@ -16,10 +16,11 @@ import {MetricsService} from "../../services/metrics.service"; import {RelationResult, ResultPreview} from "../../utils/result-preview/result-preview"; import {IndexInfoService} from "../../utils/indexInfo.service"; import {FormBuilder} from "@angular/forms"; -import {StringUtils} from "../../utils/string-utils.class"; +import {Identifier, StringUtils} from "../../utils/string-utils.class"; import {properties} from "../../../../environments/environment"; import {ISVocabulariesService} from "../../utils/staticAutoComplete/ISVocabularies.service"; import {Subscriber} from "rxjs"; +import {Session} from "../../login/utils/helper.class"; import {AnnotationComponent} from "../annotation/annotation.component"; import {User} from "../../login/utils/helper.class"; @@ -100,11 +101,15 @@ export class ResultLandingComponent { 'Title', 'Authors', 'Access rights', 'Publisher information', 'Funding Information', 'Persistent identifiers', 'Other']; + public loggedIn: boolean = false; + public pidsArrayString: string = ""; + public identifier: Identifier; + public user: User; public pid: string; @ViewChild("annotation") annotation: AnnotationComponent; - - constructor(private _resultLaningService: ResultLandingService, + + constructor(private _resultLandingService: ResultLandingService, private _vocabulariesService: ISVocabulariesService, private _piwikService: PiwikService, private route: ActivatedRoute, @@ -131,53 +136,44 @@ export class ResultLandingComponent { //this.getDivContents(); this.getPageContents(); this.updateUrl(this.properties.domain +this.properties.baseLink + this._router.url); - this.subscriptions.push(this.route.queryParams.subscribe(data => { + this.subscriptions.push(this.route.queryParams.subscribe(async data => { + if (Session.isLoggedIn()) { + this.loggedIn = true; + } this.resultLandingInfo = null; if (data['articleId']) { - this.type = "publication"; - this.updateTitle("Publication"); - this.linkToLandingPage = this.properties.searchLinkToPublication; - this.linkToSearchPage = this.properties.searchLinkToPublications; this.id = data['articleId']; - this.title = "Publication"; + this.initMetaAndLinks("publication"); } else if (data['datasetId']) { - this.updateTitle("Dataset"); - this.type = "dataset"; - this.linkToLandingPage = this.properties.searchLinkToDataset; - this.linkToSearchPage = this.properties.searchLinkToDatasets; this.id = data['datasetId']; - this.title = "Research Data"; + this.initMetaAndLinks("dataset"); } else if (data['softwareId']) { - this.updateTitle("Software"); - this.type = "software"; - this.linkToLandingPage = this.properties.searchLinkToSoftwareLanding; - this.linkToSearchPage = this.properties.searchLinkToSoftware; this.id = data['softwareId']; - this.title = "Software"; + this.initMetaAndLinks("software"); } else if (data['orpId']) { - this.type = "orp"; - this.updateTitle("Other Research Product"); - this.linkToLandingPage = this.properties.searchLinkToOrp; - this.linkToSearchPage = this.properties.searchLinkToOrps; this.id = data['orpId']; - this.title = "Other Research Product"; - } else if (data["id"]){ - this.type = "result"; + this.initMetaAndLinks("orp"); + } else if (data["id"]) { this.id = data["id"]; - this.updateTitle("Research Result"); - this.linkToLandingPage = this.properties.searchLinkToResult; - this.linkToSearchPage = this.properties.searchLinkToResults; - this.title = "Research Result"; + this.initMetaAndLinks("result"); + } else if (data["pid"]) { + this.identifier = Identifier.getIdentifierFromString(data["pid"]); + console.debug(this.identifier); + + if(!this.type) { + this.type = "result"; + } + this.initMetaAndLinks(this.type); } this.updateDescription(""); - + this.metricsClicked = false; - if (this.id && StringUtils.isOpenAIREID(this.id)) { + if ((this.id && StringUtils.isOpenAIREID(this.id)) || (this.identifier)) { this.getProvenanceVocabularyAndResultLandingInfo(); } else { this.showLoading = false; - + this._router.navigate(['/error'], { queryParams: { "page": this._location.path(true), @@ -185,14 +181,50 @@ export class ResultLandingComponent { } }); } - - this.viewsFrameUrl = this.properties.framesAPIURL + 'merge.php?com=query&data=[{"query":"resRepoViews", "resTitle":"' + this.id + '", "table":"","fields":[{"fld":"sum","agg":"sum","type":"column","yaxis":1,"c":false}],"xaxis":{"name":"month","agg":"sum"},"group":" ","color":"","type":"chart","size":200,"sort":"xaxis","xStyle":{"r":-30,"s":"6","l":"-","ft":"-","wt":"-"},"title":"","subtitle":"","xaxistitle":"Repository","yaxisheaders":["Monthly views"],"generalxaxis":"","theme":0,"in":[],"filters":[{"name":"","values":[""],"to":"-1"}]}]&info_types=["column"]&stacking=normal&steps=false&fontFamily=Courier&spacing=[5,0,0,0]&style=[{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"000000","size":""},{"color":"000000","size":""}]&backgroundColor=rgba(255,255,255,1)&colors[]=rgba(67, 67, 72, 1)&colors[]=rgba(144, 237, 125, 1)&colors[]=rgba(247, 163, 92, 1)&colors[]=rgba(128, 133, 233, 1)&colors[]=rgba(241, 92, 128, 1)&colors[]=rgba(228, 211, 84, 1)&colors[]=rgba(43, 144, 143, 1)&colors[]=rgba(244, 91, 91, 1)&colors[]=rgba(145, 232, 225, 1)&xlinew=0&ylinew=1&legends=true&tooltips=true&persistent=false'; - this.downloadsFrameUrl = this.properties.framesAPIURL + 'merge.php?com=query&data=[{"query":"resRepoDownloads", "resTitle":"' + this.id + '", "table":"","fields":[{"fld":"sum","agg":"sum","type":"column","yaxis":1,"c":false}],"xaxis":{"name":"month","agg":"sum"},"group":" ","color":"","type":"chart","size":200,"sort":"xaxis","xStyle":{"r":-30,"s":"6","l":"-","ft":"-","wt":"-"},"title":"","subtitle":"","xaxistitle":"Repository","yaxisheaders":["Monthly downloads"],"generalxaxis":"","theme":0,"in":[],"filters":[{"name":"","values":[""],"to":"-1"}]}]&info_types=["column"]&stacking=normal&steps=false&fontFamily=Courier&spacing=[5,0,0,0]&style=[{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"000000","size":""},{"color":"000000","size":""}]&backgroundColor=rgba(255,255,255,1)&colors[]=rgba(67, 67, 72, 1)&colors[]=rgba(144, 237, 125, 1)&colors[]=rgba(247, 163, 92, 1)&colors[]=rgba(128, 133, 233, 1)&colors[]=rgba(241, 92, 128, 1)&colors[]=rgba(228, 211, 84, 1)&colors[]=rgba(43, 144, 143, 1)&colors[]=rgba(244, 91, 91, 1)&colors[]=rgba(145, 232, 225, 1)&xlinew=0&ylinew=1&legends=true&tooltips=true&persistent=false'; - + + if(this.id) { + this.viewsFrameUrl = this.properties.framesAPIURL + 'merge.php?com=query&data=[{"query":"resRepoViews", "resTitle":"' + this.id + '", "table":"","fields":[{"fld":"sum","agg":"sum","type":"column","yaxis":1,"c":false}],"xaxis":{"name":"month","agg":"sum"},"group":" ","color":"","type":"chart","size":200,"sort":"xaxis","xStyle":{"r":-30,"s":"6","l":"-","ft":"-","wt":"-"},"title":"","subtitle":"","xaxistitle":"Repository","yaxisheaders":["Monthly views"],"generalxaxis":"","theme":0,"in":[],"filters":[{"name":"","values":[""],"to":"-1"}]}]&info_types=["column"]&stacking=normal&steps=false&fontFamily=Courier&spacing=[5,0,0,0]&style=[{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"000000","size":""},{"color":"000000","size":""}]&backgroundColor=rgba(255,255,255,1)&colors[]=rgba(67, 67, 72, 1)&colors[]=rgba(144, 237, 125, 1)&colors[]=rgba(247, 163, 92, 1)&colors[]=rgba(128, 133, 233, 1)&colors[]=rgba(241, 92, 128, 1)&colors[]=rgba(228, 211, 84, 1)&colors[]=rgba(43, 144, 143, 1)&colors[]=rgba(244, 91, 91, 1)&colors[]=rgba(145, 232, 225, 1)&xlinew=0&ylinew=1&legends=true&tooltips=true&persistent=false'; + this.downloadsFrameUrl = this.properties.framesAPIURL + 'merge.php?com=query&data=[{"query":"resRepoDownloads", "resTitle":"' + this.id + '", "table":"","fields":[{"fld":"sum","agg":"sum","type":"column","yaxis":1,"c":false}],"xaxis":{"name":"month","agg":"sum"},"group":" ","color":"","type":"chart","size":200,"sort":"xaxis","xStyle":{"r":-30,"s":"6","l":"-","ft":"-","wt":"-"},"title":"","subtitle":"","xaxistitle":"Repository","yaxisheaders":["Monthly downloads"],"generalxaxis":"","theme":0,"in":[],"filters":[{"name":"","values":[""],"to":"-1"}]}]&info_types=["column"]&stacking=normal&steps=false&fontFamily=Courier&spacing=[5,0,0,0]&style=[{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"000000","size":""},{"color":"000000","size":""}]&backgroundColor=rgba(255,255,255,1)&colors[]=rgba(67, 67, 72, 1)&colors[]=rgba(144, 237, 125, 1)&colors[]=rgba(247, 163, 92, 1)&colors[]=rgba(128, 133, 233, 1)&colors[]=rgba(241, 92, 128, 1)&colors[]=rgba(228, 211, 84, 1)&colors[]=rgba(43, 144, 143, 1)&colors[]=rgba(244, 91, 91, 1)&colors[]=rgba(145, 232, 225, 1)&xlinew=0&ylinew=1&legends=true&tooltips=true&persistent=false'; + } + this.scroll(); })); } - + + private initMetaAndLinks(type: string) { + if (type == "publication") { + this.type = "publication"; + this.updateTitle("Publication"); + this.linkToLandingPage = this.properties.searchLinkToPublication; + this.linkToSearchPage = this.properties.searchLinkToPublications; + this.title = "Publication"; + } else if (type == "dataset") { + this.updateTitle("Dataset"); + this.type = "dataset"; + this.linkToLandingPage = this.properties.searchLinkToDataset; + this.linkToSearchPage = this.properties.searchLinkToDatasets; + this.title = "Research Data"; + } else if (type == "software") { + this.updateTitle("Software"); + this.type = "software"; + this.linkToLandingPage = this.properties.searchLinkToSoftwareLanding; + this.linkToSearchPage = this.properties.searchLinkToSoftware; + this.title = "Software"; + } else if (type == "orp") { + this.type = "orp"; + this.updateTitle("Other Research Product"); + this.linkToLandingPage = this.properties.searchLinkToOrp; + this.linkToSearchPage = this.properties.searchLinkToOrps; + this.title = "Other Research Product"; + } else if (type == "result") { + this.type = "result"; + this.updateTitle("Research Result"); + this.linkToLandingPage = this.properties.searchLinkToResult; + this.linkToSearchPage = this.properties.searchLinkToResults; + this.title = "Research Result"; + } + } + private getPageContents() { if (this.communityId) { this.subscriptions.push(this.helper.getPageHelpContents(this.properties, this.communityId, this._router.url).subscribe(contents => { @@ -253,7 +285,7 @@ export class ResultLandingComponent { } private getOpenCitations() { - this.subscriptions.push(this._resultLaningService.getOpenCitations(this.id, this.properties).subscribe( + this.subscriptions.push(this._resultLandingService.getOpenCitations(this.id, this.properties).subscribe( data => { this.resultLandingInfo.openCitations = data[1]; }, @@ -276,7 +308,7 @@ export class ResultLandingComponent { this.getResultLandingInfo(provenanceActionVocabulary); }, err => { this.getResultLandingInfo(null); - this.handleError("Error getting provenance action vocabulary for " + this.type + " with id: " + this.id, err); + this.handleError("Error getting provenance action vocabulary for " + this.type, err); } )); } else { @@ -324,9 +356,14 @@ export class ResultLandingComponent { // } private getResultLandingInfo(provenanceActionVocabulary: any) { - this.subscriptions.push(this._resultLaningService.getResultLandingInfo(this.id, this.type, provenanceActionVocabulary, this.properties).subscribe( + this.subscriptions.push(this._resultLandingService.getResultLandingInfo(this.id, this.identifier, this.type, provenanceActionVocabulary, this.properties).subscribe( data => { this.resultLandingInfo = data; + if(!this.id) { + this.id = this.resultLandingInfo.relcanId; + this.viewsFrameUrl = this.properties.framesAPIURL + 'merge.php?com=query&data=[{"query":"resRepoViews", "resTitle":"' + this.id + '", "table":"","fields":[{"fld":"sum","agg":"sum","type":"column","yaxis":1,"c":false}],"xaxis":{"name":"month","agg":"sum"},"group":" ","color":"","type":"chart","size":200,"sort":"xaxis","xStyle":{"r":-30,"s":"6","l":"-","ft":"-","wt":"-"},"title":"","subtitle":"","xaxistitle":"Repository","yaxisheaders":["Monthly views"],"generalxaxis":"","theme":0,"in":[],"filters":[{"name":"","values":[""],"to":"-1"}]}]&info_types=["column"]&stacking=normal&steps=false&fontFamily=Courier&spacing=[5,0,0,0]&style=[{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"000000","size":""},{"color":"000000","size":""}]&backgroundColor=rgba(255,255,255,1)&colors[]=rgba(67, 67, 72, 1)&colors[]=rgba(144, 237, 125, 1)&colors[]=rgba(247, 163, 92, 1)&colors[]=rgba(128, 133, 233, 1)&colors[]=rgba(241, 92, 128, 1)&colors[]=rgba(228, 211, 84, 1)&colors[]=rgba(43, 144, 143, 1)&colors[]=rgba(244, 91, 91, 1)&colors[]=rgba(145, 232, 225, 1)&xlinew=0&ylinew=1&legends=true&tooltips=true&persistent=false'; + this.downloadsFrameUrl = this.properties.framesAPIURL + 'merge.php?com=query&data=[{"query":"resRepoDownloads", "resTitle":"' + this.id + '", "table":"","fields":[{"fld":"sum","agg":"sum","type":"column","yaxis":1,"c":false}],"xaxis":{"name":"month","agg":"sum"},"group":" ","color":"","type":"chart","size":200,"sort":"xaxis","xStyle":{"r":-30,"s":"6","l":"-","ft":"-","wt":"-"},"title":"","subtitle":"","xaxistitle":"Repository","yaxisheaders":["Monthly downloads"],"generalxaxis":"","theme":0,"in":[],"filters":[{"name":"","values":[""],"to":"-1"}]}]&info_types=["column"]&stacking=normal&steps=false&fontFamily=Courier&spacing=[5,0,0,0]&style=[{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"rgba(0, 0, 0, 1)","size":"18"},{"color":"000000","size":""},{"color":"000000","size":""}]&backgroundColor=rgba(255,255,255,1)&colors[]=rgba(67, 67, 72, 1)&colors[]=rgba(144, 237, 125, 1)&colors[]=rgba(247, 163, 92, 1)&colors[]=rgba(128, 133, 233, 1)&colors[]=rgba(241, 92, 128, 1)&colors[]=rgba(228, 211, 84, 1)&colors[]=rgba(43, 144, 143, 1)&colors[]=rgba(244, 91, 91, 1)&colors[]=rgba(145, 232, 225, 1)&xlinew=0&ylinew=1&legends=true&tooltips=true&persistent=false'; + } if (this.type == "result") { // no type was specified - update URL based this.resultLandingInfo.resultType this.updateUrlWithType(); } @@ -351,21 +388,27 @@ export class ResultLandingComponent { } this.bioentitiesNum = bioentitiesNum; if (typeof document !== 'undefined') { - if (this.resultLandingInfo.identifiers != undefined && this.resultLandingInfo.identifiers.has('doi')) { - this.doi = this.resultLandingInfo.identifiers.get('doi')[0]; - this.subscriptions.push(this.metricsService.hasAltMetrics(this.properties.altMetricsAPIURL, this.doi).subscribe(hasAltMetrics => { - this.hasAltMetrics = hasAltMetrics; - }, error => { - this.hasAltMetrics = false; - })); + if(this.resultLandingInfo.identifiers) { + let pidsArray: string[] = []; + for(let key of Array.from(this.resultLandingInfo.identifiers.keys())) { + pidsArray = pidsArray.concat(this.resultLandingInfo.identifiers.get(key)); + this.pidsArrayString = pidsArray.join(); + } + if (this.resultLandingInfo.identifiers.has('doi')) { + this.doi = this.resultLandingInfo.identifiers.get('doi')[0]; + this.subscriptions.push(this.metricsService.hasAltMetrics(this.properties.altMetricsAPIURL, this.doi).subscribe(hasAltMetrics => { + this.hasAltMetrics = hasAltMetrics; + }, error => { + this.hasAltMetrics = false; + })); + } } } this.showLoading = false; this.setActiveTab(); }, err => { - this.handleError("Error getting " + this.type + " for id: " + this.id, err); - + this.handleError("Error getting " + this.type + " for " + (this.id ? ("id: " + this.id) : ("pid: " + this.identifier.id + " ("+this.identifier.class+")")), err); if (err.status == 404) { this._router.navigate(['/error'], {queryParams: {"page": this._location.path(true), "page_type": this.type}}); } @@ -526,6 +569,7 @@ export class ResultLandingComponent { updateUrlWithType() { this.type = this.resultLandingInfo.resultType; + if (this.type == "publication") { this.linkToLandingPage = this.properties.searchLinkToPublication; this.linkToSearchPage = this.properties.searchLinkToPublications; @@ -540,7 +584,12 @@ export class ResultLandingComponent { this.linkToLandingPage = this.properties.searchLinkToOrp; this.linkToSearchPage = this.properties.searchLinkToOrps; } - this._location.go(this.linkToLandingPage + this.id); + if(!this.identifier) { + this._location.go(this.linkToLandingPage + this.id); + } + // else { + // this._location.go(this.linkToLandingPage.split("?")[0] + "?pid=" + this.identifier.id); + // } } public getReferenceUrl(id: Id): string { diff --git a/landingPages/result/resultLanding.service.ts b/landingPages/result/resultLanding.service.ts index 73b92de9..37d7a273 100644 --- a/landingPages/result/resultLanding.service.ts +++ b/landingPages/result/resultLanding.service.ts @@ -6,7 +6,8 @@ import {EnvProperties} from '../../utils/properties/env-properties'; import {ParsingFunctions} from '../landing-utils/parsingFunctions.class'; import {map} from "rxjs/operators"; import {HostedByCollectedFrom, Organization} from "../../utils/result-preview/result-preview"; -import {Dates} from "../../utils/string-utils.class"; +import {Dates, Identifier} from "../../utils/string-utils.class"; +import {properties} from "../../../../environments/environment"; @Injectable() export class ResultLandingService { @@ -18,22 +19,62 @@ export class ResultLandingService { public parsingFunctions: ParsingFunctions; resultLandingInfo: ResultLandingInfo; - getResultLandingInfo (id: string, type: string, provenanceActionVocabulary: any, properties: EnvProperties): any { - let url = properties.searchAPIURLLAst; - if (type === 'publication') { - url += 'publications/'; - } else if (type === 'dataset') { - url += 'datasets/'; - } else if (type === 'software') { - url += 'software/'; - } else if (type === 'orp') { - url += 'other/'; - } else if (type === 'result') { - url += 'results/'; + private buildResultLandingInfoUrl(id: string, identifier: Identifier, type: string): string { + if (id) { + let url = properties.searchAPIURLLAst; + if (type === 'publication') { + url += 'publications/'; + } else if (type === 'dataset') { + url += 'datasets/'; + } else if (type === 'software') { + url += 'software/'; + } else if (type === 'orp') { + url += 'other/'; + } else if (type === 'result') { + url += 'results/'; + } + url += id + '?format=json'; + return url; + } else if (identifier) { + // pid = "10.3389/fphys.2014.00466"; + let url = properties.searchAPIURLLAst + "resources2"; + url += "?pid="+identifier.id + "&pidtype=" + identifier.class + "&type="; + if (type === 'publication') { + url += 'publications'; + } else if (type === 'dataset') { + url += 'datasets'; + } else if (type === 'software') { + url += 'software'; + } else if (type === 'orp') { + url += 'other'; + } else if (type === 'result') { + url += 'results'; + } + url += "&format=json"; + return url; } - url += id + '?format=json'; + } - return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) + getResultLandingInfo (id: string, identifier: Identifier, type: string, provenanceActionVocabulary: any, properties: EnvProperties): any { + let url: string = this.buildResultLandingInfoUrl(id, identifier, type); + + let finalUrl: string = (properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url; + return this.http.get(finalUrl) + .pipe(map(res => { + if(!id && identifier) { + if(!res['results'] || res['results'].length == 0) { + throw new HttpErrorResponse({ + status: 404, + statusText: "Not found", + url: finalUrl, + error: "Http failure response for "+finalUrl+": 404 Not Found" + }); + } + return res['results'][0]; + } else { + return res; + } + })) .pipe(map(res => [res['result']['header']['dri:status'], res['result']['metadata']['oaf:entity'], res])) .pipe(map(res => [ res[1]['oaf:result'], // 0 @@ -238,6 +279,9 @@ export class ResultLandingService { // res['result']['metadata']['oaf:entity']['oaf:result']['language'] if(data[6] != null) { this.resultLandingInfo.languages = this.parsingFunctions.parseLanguages(data[6]); + // let languagesAndCodes: string[][] = this.parsingFunctions.parseLanguages(data[6]); + // this.resultLandingInfo.languages = languagesAndCodes[0]; + // this.resultLandingInfo.languageCodes = languagesAndCodes[1]; } // res['result']['metadata']['oaf:entity']['oaf:result']['country'] diff --git a/utils/string-utils.class.ts b/utils/string-utils.class.ts index 04a1a77b..e4796a69 100644 --- a/utils/string-utils.class.ts +++ b/utils/string-utils.class.ts @@ -134,21 +134,29 @@ export class Identifier { for (let id of words) { if (id.length > 0) { - if (Identifier.isValidDOI(id)) { - identifiers.push({"class": "doi", "id": id}) - } else if (Identifier.isValidORCID(id)) { - identifiers.push({"class": "ORCID", "id": id}) - } else if (Identifier.isValidPMCID(id)) { - identifiers.push({"class": "pmc", "id": id}) - } else if (Identifier.isValidPMID(id)) { - identifiers.push({"class": "pmid", "id": id}) - } else if (Identifier.isValidHANDLE(id)) { - identifiers.push({"class": "handle", "id": id}) + let identifier: Identifier = this.getIdentifierFromString(id); + if(identifier) { + identifiers.push(identifier); } } } return identifiers; } + + public static getIdentifierFromString(pid: string): Identifier { + if (Identifier.isValidDOI(pid)) { + return {"class": "doi", "id": pid}; + } else if (Identifier.isValidORCID(pid)) { + return {"class": "ORCID", "id": pid}; + } else if (Identifier.isValidPMCID(pid)) { + return {"class": "pmc", "id": pid}; + } else if (Identifier.isValidPMID(pid)) { + return {"class": "pmid", "id": pid}; + } else if (Identifier.isValidHANDLE(pid)) { + return {"class": "handle", "id": pid}; + } + return null; + } public static isValidDOI(str: string): boolean { var exp1 = /\b(10[.][0-9]{4,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)\b/g