@tekkare/romulus 0.1.250 → 0.1.252
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/components/BarChart.vue +1 -0
- package/dist/runtime/components/ChoroplethMap.vue +4 -1
- package/dist/runtime/internal/geo/fr-regions.json +1 -1
- package/dist/runtime/utils/chart.d.ts +6 -3
- package/dist/runtime/utils/chart.js +15 -2
- package/layer/app/app.config.ts +6 -0
- package/layer/app/components/OipPubmedSummary.vue +223 -0
- package/layer/app/components/OipResourceDrawer.vue +331 -0
- package/layer/app/components/OipResourceDrawerLink.vue +40 -0
- package/layer/app/components/OipResourceField.vue +41 -0
- package/layer/app/components/OipResourceGenericCard.vue +54 -0
- package/layer/app/components/OipResourceSource.vue +50 -0
- package/layer/app/components/OipResourceTags.vue +65 -0
- package/layer/app/components/OipResourceView.vue +107 -0
- package/layer/app/components/oip-drugs/fiches/AssociationFiche.vue +775 -0
- package/layer/app/components/oip-drugs/fiches/BrandFiche.vue +1111 -0
- package/layer/app/components/oip-drugs/fiches/IndicationFiche.vue +182 -0
- package/layer/app/components/oip-drugs/fiches/JoFiche.vue +101 -0
- package/layer/app/components/oip-drugs/fiches/PndsFiche.vue +279 -0
- package/layer/app/components/oip-drugs/heart/JoCard.vue +314 -0
- package/layer/app/components/oip-drugs/heart/TextHighlight.vue +326 -0
- package/layer/app/components/oip-drugs/heart/ansm/BrandCard.vue +187 -0
- package/layer/app/components/oip-drugs/heart/ansm/CisDetail.vue +363 -0
- package/layer/app/components/oip-drugs/heart/ansm/CisTable.vue +167 -0
- package/layer/app/components/oip-drugs/heart/associations/NationalAssemblyCard.vue +373 -0
- package/layer/app/components/oip-drugs/heart/associations/NationalAssemblyFiche.vue +372 -0
- package/layer/app/components/oip-drugs/heart/associations/TranscriptionCard.vue +55 -0
- package/layer/app/components/oip-drugs/heart/elastic/SourceContainerElastic.vue +103 -0
- package/layer/app/components/oip-drugs/heart/france/BrandGroupCard.vue +450 -0
- package/layer/app/components/oip-drugs/heart/mitm/Card.vue +199 -0
- package/layer/app/components/oip-drugs/heart/mitm/Source.vue +23 -0
- package/layer/app/components/oip-drugs/heart/mitm/details/Overview.vue +381 -0
- package/layer/app/components/oip-drugs/heart/put/Card.vue +212 -0
- package/layer/app/components/oip-drugs/heart/results/AccesCard.vue +696 -0
- package/layer/app/components/oip-drugs/heart/results/AlertCard.vue +342 -0
- package/layer/app/components/oip-drugs/heart/results/AsmrCursor.vue +229 -0
- package/layer/app/components/oip-drugs/heart/results/EvalCard.vue +370 -0
- package/layer/app/components/oip-drugs/heart/results/IndicCard.vue +743 -0
- package/layer/app/components/oip-drugs/heart/results/MatchExplain.vue +243 -0
- package/layer/app/components/oip-drugs/heart/results/PrefRows.vue +105 -0
- package/layer/app/components/oip-drugs/heart/results/details/HasHistory.vue +487 -0
- package/layer/app/components/oip-drugs/heart/results/details/InternationalCountryCard.vue +461 -0
- package/layer/app/components/oip-drugs/heart/results/details/InternationalOverview.vue +200 -0
- package/layer/app/components/oip-drugs/heart/results/details/InternationalPriceDrawer.vue +647 -0
- package/layer/app/components/oip-drugs/heart/results/details/Monograph.vue +128 -0
- package/layer/app/components/oip-drugs/heart/results/details/OpinionDrawer.vue +535 -0
- package/layer/app/components/oip-drugs/heart/results/details/PresentationDrawer.vue +738 -0
- package/layer/app/components/oip-drugs/heart/results/details/Price.vue +227 -0
- package/layer/app/components/oip-drugs/heart/results/details/PriceOverview.vue +1261 -0
- package/layer/app/components/oip-drugs/heart/results/details/RecordDrawer.vue +494 -0
- package/layer/app/components/oip-drugs/heart/results/details/RecordList.vue +426 -0
- package/layer/app/components/oip-drugs/heart/results/les/Card.vue +340 -0
- package/layer/app/components/oip-drugs/heart/results/les/Drawer.vue +67 -0
- package/layer/app/components/oip-drugs/heart/results/les/IndicationDetail.vue +149 -0
- package/layer/app/components/oip-drugs/heart/results/les/Source.vue +20 -0
- package/layer/app/components/oip-drugs/heart/results/les/SourceTag.vue +39 -0
- package/layer/app/components/oip-drugs/heart/searchPage/DynamicSource.vue +29 -0
- package/layer/app/components/oip-drugs/medicam/market/Chart.vue +121 -0
- package/layer/app/components/oip-drugs/outpatient/ProductEvolution.vue +236 -0
- package/layer/app/components/oip-drugs/resources/Ansm.vue +75 -0
- package/layer/app/components/oip-drugs/resources/Association.vue +30 -0
- package/layer/app/components/oip-drugs/resources/Brand.vue +65 -0
- package/layer/app/components/oip-drugs/resources/Contribution.vue +216 -0
- package/layer/app/components/oip-drugs/resources/Hospital.vue +151 -0
- package/layer/app/components/oip-drugs/resources/Indication.vue +54 -0
- package/layer/app/components/oip-drugs/resources/Jo.vue +57 -0
- package/layer/app/components/oip-drugs/resources/Medicam.vue +140 -0
- package/layer/app/components/oip-drugs/resources/Mitm.vue +84 -0
- package/layer/app/components/oip-drugs/resources/NationalAssembly.vue +93 -0
- package/layer/app/components/oip-drugs/resources/Outpatient.vue +97 -0
- package/layer/app/components/oip-drugs/resources/Pnds.vue +24 -0
- package/layer/app/components/oip-drugs/resources/Price.vue +106 -0
- package/layer/app/components/oip-drugs/resources/Put.vue +143 -0
- package/layer/app/components/oip-science/appel-a-projet/Cards.vue +162 -0
- package/layer/app/components/oip-science/clinical-trials/Cards.vue +382 -0
- package/layer/app/components/oip-science/clinical-trials/CardsGlobal.vue +273 -0
- package/layer/app/components/oip-science/clinical-trials/LinkedList.vue +366 -0
- package/layer/app/components/oip-science/clinical-trials/PairBadge.vue +25 -0
- package/layer/app/components/oip-science/clinical-trials/PairBody.vue +182 -0
- package/layer/app/components/oip-science/clinical-trials/SitesDrawer.vue +95 -0
- package/layer/app/components/oip-science/common/Form.vue +73 -0
- package/layer/app/components/oip-science/common/MatchAvgTag.vue +283 -0
- package/layer/app/components/oip-science/common/NoData.vue +16 -0
- package/layer/app/components/oip-science/common/ScoreBadge.vue +35 -0
- package/layer/app/components/oip-science/common/Source.vue +31 -0
- package/layer/app/components/oip-science/common/TableTags.vue +279 -0
- package/layer/app/components/oip-science/common/Timeline.vue +104 -0
- package/layer/app/components/oip-science/common/ToolTips.vue +89 -0
- package/layer/app/components/oip-science/cross/publicationPubmed.vue +484 -0
- package/layer/app/components/oip-science/crossData/CrossDataLocations.vue +71 -0
- package/layer/app/components/oip-science/ctgov/Investigators.vue +148 -0
- package/layer/app/components/oip-science/ctgov/Locations.vue +102 -0
- package/layer/app/components/oip-science/ctgov/Publications.vue +52 -0
- package/layer/app/components/oip-science/ctgov/Sponsors.vue +66 -0
- package/layer/app/components/oip-science/ctgov/StudyDescription.vue +1136 -0
- package/layer/app/components/oip-science/ctgov-centers/ClinicalTrials.vue +40 -0
- package/layer/app/components/oip-science/ctgov-centers/Publications.vue +50 -0
- package/layer/app/components/oip-science/ctgov-investigators/ClinicalTrials.vue +43 -0
- package/layer/app/components/oip-science/ctgov-investigators/Informations.vue +171 -0
- package/layer/app/components/oip-science/ctgov-investigators/Publications.vue +44 -0
- package/layer/app/components/oip-science/elastic/DateRangeFilter.vue +209 -0
- package/layer/app/components/oip-science/elastic/Filter.vue +719 -0
- package/layer/app/components/oip-science/elastic/MatchExplain.vue +152 -0
- package/layer/app/components/oip-science/establishments/Cards.vue +183 -0
- package/layer/app/components/oip-science/establishments/ClinicalTrials.vue +62 -0
- package/layer/app/components/oip-science/establishments/Hcps.vue +227 -0
- package/layer/app/components/oip-science/establishments/Informations.vue +263 -0
- package/layer/app/components/oip-science/establishments/LinkedList.vue +153 -0
- package/layer/app/components/oip-science/establishments/MatchedLabels.vue +194 -0
- package/layer/app/components/oip-science/establishments/PublicFinance.vue +62 -0
- package/layer/app/components/oip-science/euct/Investigators.vue +125 -0
- package/layer/app/components/oip-science/euct/Locations.vue +102 -0
- package/layer/app/components/oip-science/euct/Products.vue +101 -0
- package/layer/app/components/oip-science/euct/Publications.vue +89 -0
- package/layer/app/components/oip-science/euct/Sponsors.vue +86 -0
- package/layer/app/components/oip-science/euct/StudyDescription.vue +1075 -0
- package/layer/app/components/oip-science/euct-centers/ClinicalTrials.vue +40 -0
- package/layer/app/components/oip-science/euct-centers/Publications.vue +55 -0
- package/layer/app/components/oip-science/euct-investigators/ClinicalTrials.vue +41 -0
- package/layer/app/components/oip-science/euct-investigators/Informations.vue +171 -0
- package/layer/app/components/oip-science/euct-investigators/Publications.vue +51 -0
- package/layer/app/components/oip-science/hcps/AppelsAProjet.vue +62 -0
- package/layer/app/components/oip-science/hcps/Cards.vue +237 -0
- package/layer/app/components/oip-science/hcps/ClinicalTrials.vue +78 -0
- package/layer/app/components/oip-science/hcps/Informations.vue +296 -0
- package/layer/app/components/oip-science/hcps/LinkedList.vue +153 -0
- package/layer/app/components/oip-science/hcps/MatchedLabels.vue +207 -0
- package/layer/app/components/oip-science/hcps/Pubmed.vue +128 -0
- package/layer/app/components/oip-science/local/SliderTabs.vue +99 -0
- package/layer/app/components/oip-science/local/SliderTabsFull.vue +135 -0
- package/layer/app/components/oip-science/pubmed/Authors.vue +128 -0
- package/layer/app/components/oip-science/pubmed/Cards.vue +417 -0
- package/layer/app/components/oip-science/pubmed/ClinicalTrials.vue +71 -0
- package/layer/app/components/oip-science/resources/Phrc.vue +39 -0
- package/layer/app/composables/useOipChapterScroll.ts +43 -0
- package/layer/app/composables/useOipResourceHooks.ts +27 -0
- package/layer/app/composables/useOipResourceNav.ts +66 -0
- package/layer/app/composables/useOipResourceViews.ts +117 -0
- package/layer/app/composables/useOipResources.ts +83 -0
- package/layer/app/oip-drugs/PORTING.md +120 -0
- package/layer/app/oip-drugs/composables/useAssociationDetail.ts +220 -0
- package/layer/app/oip-drugs/composables/useAssociationExport.ts +63 -0
- package/layer/app/oip-drugs/composables/useAssociationLookup.ts +105 -0
- package/layer/app/oip-drugs/composables/useCardPrefOptions.ts +201 -0
- package/layer/app/oip-drugs/composables/useCurrency.ts +121 -0
- package/layer/app/oip-drugs/composables/useDirectusSources.ts +224 -0
- package/layer/app/oip-drugs/composables/useHeartBrandMatches.ts +112 -0
- package/layer/app/oip-drugs/composables/useHeartDetailSearches.ts +479 -0
- package/layer/app/oip-drugs/composables/useHeartIntlApprovals.ts +661 -0
- package/layer/app/oip-drugs/composables/useHeartLesIndication.ts +168 -0
- package/layer/app/oip-drugs/composables/useHeartMatchExplain.ts +231 -0
- package/layer/app/oip-drugs/composables/useHeartReports.ts +239 -0
- package/layer/app/oip-drugs/composables/useHeartSearchFields.ts +233 -0
- package/layer/app/oip-drugs/composables/useMergeByKey.ts +23 -0
- package/layer/app/oip-drugs/composables/useOipDrugsElastic.ts +621 -0
- package/layer/app/oip-drugs/composables/usePageEmpty.ts +58 -0
- package/layer/app/oip-drugs/composables/v-useSalesSource.ts +64 -0
- package/layer/app/oip-drugs/drugs.css +500 -0
- package/layer/app/oip-drugs/esIndices.ts +322 -0
- package/layer/app/oip-drugs/kinds.ts +264 -0
- package/layer/app/oip-drugs/locales/en.json +1571 -0
- package/layer/app/oip-drugs/locales/fr.json +1571 -0
- package/layer/app/oip-drugs/monographs/blincyto-has.vue +289 -0
- package/layer/app/oip-drugs/monographs/darzalex-has.vue +276 -0
- package/layer/app/oip-drugs/monographs/dupixent-has.vue +216 -0
- package/layer/app/oip-drugs/monographs/enhertu-has.vue +280 -0
- package/layer/app/oip-drugs/monographs/has-sein-2023.vue +1649 -0
- package/layer/app/oip-drugs/monographs/ibrance-has.vue +277 -0
- package/layer/app/oip-drugs/monographs/imfinzi-has.vue +293 -0
- package/layer/app/oip-drugs/monographs/keytruda-has.vue +334 -0
- package/layer/app/oip-drugs/monographs/kisqali-has.vue +201 -0
- package/layer/app/oip-drugs/monographs/opdivo-has.vue +231 -0
- package/layer/app/oip-drugs/monographs/ozempic-has.vue +186 -0
- package/layer/app/oip-drugs/monographs/tecentriq-has.vue +312 -0
- package/layer/app/oip-drugs/monographs/yescarta-has.vue +272 -0
- package/layer/app/oip-drugs/types/elastic.ts +113 -0
- package/layer/app/oip-drugs/types/es/agencies.ts +152 -0
- package/layer/app/oip-drugs/types/es/directory.ts +54 -0
- package/layer/app/oip-drugs/types/es/docByIndex.ts +151 -0
- package/layer/app/oip-drugs/types/es/openmedic.ts +67 -0
- package/layer/app/oip-drugs/types/es/outpatient.ts +71 -0
- package/layer/app/oip-drugs/types/es/portal.ts +130 -0
- package/layer/app/oip-drugs/types/es/retail.ts +107 -0
- package/layer/app/oip-drugs/types/es/statistics.ts +29 -0
- package/layer/app/oip-drugs/types/heart/CurrencyRate.ts +16 -0
- package/layer/app/oip-drugs/types/heart/ansm.ts +106 -0
- package/layer/app/oip-drugs/types/heart/tag.ts +29 -0
- package/layer/app/oip-drugs/utils/associationFields.ts +118 -0
- package/layer/app/oip-drugs/utils/contributions.ts +36 -0
- package/layer/app/oip-drugs/utils/countryMapping.ts +387 -0
- package/layer/app/oip-drugs/utils/esHighlight.ts +21 -0
- package/layer/app/oip-drugs/utils/exportSheets.ts +57 -0
- package/layer/app/oip-drugs/utils/heartIntlPrice.ts +228 -0
- package/layer/app/oip-drugs/utils/heartStyleAndFormat.ts +262 -0
- package/layer/app/oip-drugs/utils/heartStyleAnsm.ts +71 -0
- package/layer/app/oip-drugs/utils/latestDate.ts +31 -0
- package/layer/app/oip-drugs/utils/p-heartCardTags.ts +53 -0
- package/layer/app/oip-drugs/utils/priceExport.ts +269 -0
- package/layer/app/oip-drugs/utils/q-hasRatings.ts +43 -0
- package/layer/app/oip-drugs/utils/s-openCard.ts +20 -0
- package/layer/app/oip-drugs/utils/sourceUuids.ts +155 -0
- package/layer/app/oip-drugs/utils/styleAndFormat.ts +40 -0
- package/layer/app/oip-drugs/utils/v-salesSeries.ts +156 -0
- package/layer/app/oip-drugs/utils/v-scopeTags.ts +23 -0
- package/layer/app/oip-science/PORTING.md +93 -0
- package/layer/app/oip-science/assets/smartSelection.json +428 -0
- package/layer/app/oip-science/composables/useAuthorMatching.ts +342 -0
- package/layer/app/oip-science/composables/useCTCenter.ts +107 -0
- package/layer/app/oip-science/composables/useCTInvestigators.ts +107 -0
- package/layer/app/oip-science/composables/useEstablishmentCrossData.ts +139 -0
- package/layer/app/oip-science/composables/useEstablishmentMatching.ts +176 -0
- package/layer/app/oip-science/composables/useEuct.ts +418 -0
- package/layer/app/oip-science/composables/useEuctCenter.ts +107 -0
- package/layer/app/oip-science/composables/useEuctInvestigators.ts +107 -0
- package/layer/app/oip-science/composables/useGlobalClinicalTrials.ts +624 -0
- package/layer/app/oip-science/composables/useLinkedTrials.ts +83 -0
- package/layer/app/oip-science/composables/useOipElastic.ts +658 -0
- package/layer/app/oip-science/composables/useOipSearchExplain.ts +166 -0
- package/layer/app/oip-science/composables/usePubmed.ts +487 -0
- package/layer/app/oip-science/composables/useSearchFields.ts +153 -0
- package/layer/app/oip-science/indexConfig.json +794 -0
- package/layer/app/oip-science/locales/en.json +483 -0
- package/layer/app/oip-science/locales/fr.json +483 -0
- package/layer/app/oip-science/science.css +1182 -0
- package/layer/app/oip-science/utils/a-openCard.ts +23 -0
- package/layer/app/oip-science/utils/b-openCard.ts +35 -0
- package/layer/app/oip-science/utils/c-filterContext.ts +81 -0
- package/layer/app/oip-science/utils/f-types.ts +241 -0
- package/layer/app/oip-science/utils/frDiseaseTerms.ts +269 -0
- package/layer/app/oip-science/utils/matchMethod.ts +53 -0
- package/layer/app/oip-science/utils/sliderTabs.ts +13 -0
- package/layer/app/oip-science/utils/sources.ts +15 -0
- package/layer/app/oip-science/utils/styleAndFormat.ts +608 -0
- package/layer/app/oip-science/utils/toPresets.ts +7 -0
- package/layer/app/oip-science/utils/valueTable.ts +126 -0
- package/layer/app/plugins/oip-science-i18n.ts +17 -0
- package/layer/app/utils/oipFicheRoutes.ts +118 -0
- package/layer/app/utils/oipResources.ts +440 -0
- package/layer/nuxt.config.ts +22 -2
- package/layer/public/reports/blincyto-has.html +292 -0
- package/layer/public/reports/blincyto-has.pdf +0 -0
- package/layer/public/reports/darzalex-has.html +279 -0
- package/layer/public/reports/darzalex-has.pdf +0 -0
- package/layer/public/reports/dupixent-has.html +217 -0
- package/layer/public/reports/dupixent-has.pdf +0 -0
- package/layer/public/reports/enhertu-has.html +283 -0
- package/layer/public/reports/enhertu-has.pdf +0 -0
- package/layer/public/reports/has-sein-2023.html +1639 -0
- package/layer/public/reports/ibrance-has.html +280 -0
- package/layer/public/reports/ibrance-has.pdf +0 -0
- package/layer/public/reports/imfinzi-has.html +297 -0
- package/layer/public/reports/imfinzi-has.pdf +0 -0
- package/layer/public/reports/keytruda-has.html +337 -0
- package/layer/public/reports/keytruda-has.pdf +0 -0
- package/layer/public/reports/kisqali-has.html +202 -0
- package/layer/public/reports/kisqali-has.pdf +0 -0
- package/layer/public/reports/opdivo-has.html +232 -0
- package/layer/public/reports/opdivo-has.pdf +0 -0
- package/layer/public/reports/ozempic-has.html +188 -0
- package/layer/public/reports/ozempic-has.pdf +0 -0
- package/layer/public/reports/tecentriq-has.html +315 -0
- package/layer/public/reports/tecentriq-has.pdf +0 -0
- package/layer/public/reports/yescarta-has.html +275 -0
- package/layer/public/reports/yescarta-has.pdf +0 -0
- package/layer/server/api/oip/es.post.ts +99 -0
- package/layer/server/api/oip/pdf.get.ts +70 -0
- package/layer/server/api/oip/reports.get.ts +98 -0
- package/layer/server/api/oip/resource-types.get.ts +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Une publication du Journal Officiel pour une presentation (CIP/UCD).
|
|
3
|
+
|
|
4
|
+
Meme en-tete que les autres cartes de resultat du hub (marque, MITM, LES) :
|
|
5
|
+
le titre au palier des cartes, le laboratoire et le circuit en sous-titre, le
|
|
6
|
+
compte en pastille a droite, la source en pied. L'export de la carte se
|
|
7
|
+
demande par la roue crantee, comme partout ailleurs, pas par un bouton qui
|
|
8
|
+
lui serait propre.
|
|
9
|
+
|
|
10
|
+
Porte de `heart/joCard.vue` de fr_drugs_app.
|
|
11
|
+
-->
|
|
12
|
+
<template>
|
|
13
|
+
<RmTableCard class="oip-drugs" :lang="dateLang" :payload="exportPayload">
|
|
14
|
+
<template #header>
|
|
15
|
+
<div class="jo_identity">
|
|
16
|
+
<h3 class="rm-table-card__title">{{ product.label }}</h3>
|
|
17
|
+
<p class="jo_meta">
|
|
18
|
+
{{ product.manufacturer }}
|
|
19
|
+
<template v-if="product.distribution_channel">
|
|
20
|
+
· {{ product.distribution_channel }}
|
|
21
|
+
</template>
|
|
22
|
+
</p>
|
|
23
|
+
<p v-if="lastPrice?.jorf_code || lastPrice?.nor_code" class="jo_refs">
|
|
24
|
+
<span v-if="lastPrice?.jorf_code">JORF {{ lastPrice.jorf_code }}</span>
|
|
25
|
+
<span v-if="lastPrice?.jorf_code && lastPrice?.nor_code"> · </span>
|
|
26
|
+
<span v-if="lastPrice?.nor_code">NOR {{ lastPrice.nor_code }}</span>
|
|
27
|
+
</p>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="jo_actions">
|
|
31
|
+
<!-- Emplacement libre pour un appelant (la fiche projet y pose son
|
|
32
|
+
bouton « Commenter ») avant le bouton projet : vide partout ailleurs. -->
|
|
33
|
+
<slot name="hubr-actions" />
|
|
34
|
+
<!-- La liste JO passe par le second cluster, qui range l'`_id` du
|
|
35
|
+
document dans `id` (cf. mapHits de useOipDrugsElastic). -->
|
|
36
|
+
<component
|
|
37
|
+
:is="projectButton"
|
|
38
|
+
v-if="projectButton"
|
|
39
|
+
:resource-id="product._id ?? product.id"
|
|
40
|
+
type="FrDrugPriceJo"
|
|
41
|
+
:label="product.label"
|
|
42
|
+
compact
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="jo_facts">
|
|
47
|
+
<span class="jo_count">{{ countLabel }}</span>
|
|
48
|
+
<span v-if="lastPrice?.announce_date" class="jo_date">
|
|
49
|
+
{{ locale === "fr" ? "Dernière publication" : "Latest publication" }} :
|
|
50
|
+
<RmDate :date="lastPrice.announce_date" :lang="dateLang" />
|
|
51
|
+
</span>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<RmTable :columns="table.columns" :rows="table.rows">
|
|
56
|
+
<template v-for="key in table.typeKeys.Date" :key="key" #[key]="{ value }">
|
|
57
|
+
<RmDate :lang="dateLang" :date="value" />
|
|
58
|
+
</template>
|
|
59
|
+
<template v-for="key in table.typeKeys.Code" :key="key" #[key]="{ value }">
|
|
60
|
+
<span>{{ value.join(" - ") }}</span>
|
|
61
|
+
</template>
|
|
62
|
+
<!-- Memes montants que le suivi des prix : format monetaire complet, et
|
|
63
|
+
« NA » quand le tarif n'existe pas (un « € » seul se lisait comme
|
|
64
|
+
un prix nul). Un `<p>` ici prenait la marge du reset et decalait la
|
|
65
|
+
cellule d'une demi-ligne par rapport a ses voisines. -->
|
|
66
|
+
<template v-for="key in table.typeKeys.Price" :key="key" #[key]="{ value }">
|
|
67
|
+
<span>{{ money(value) }}</span>
|
|
68
|
+
</template>
|
|
69
|
+
</RmTable>
|
|
70
|
+
|
|
71
|
+
<!-- Meme pied que les cartes de marque, MITM et LES : la source, et rien
|
|
72
|
+
d'autre. La gouttiere vient de RmTableCard. -->
|
|
73
|
+
<div class="jo_footer">
|
|
74
|
+
<OipDrugsHeartElasticSourceContainerElastic
|
|
75
|
+
:uuid="HEART_SOURCE_UUIDS.ACTUALITE_JO"
|
|
76
|
+
:last-label="$t('oipDrugs.heart.sources.lastPrice')"
|
|
77
|
+
:last-date="lastPrice?.announce_date"
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
</RmTableCard>
|
|
81
|
+
</template>
|
|
82
|
+
|
|
83
|
+
<script setup lang="ts">
|
|
84
|
+
import { HEART_SOURCE_UUIDS } from "../../../oip-drugs/utils/sourceUuids";
|
|
85
|
+
import { valueTable } from "../../../utils/valueTable";
|
|
86
|
+
|
|
87
|
+
const props = defineProps({
|
|
88
|
+
product: {
|
|
89
|
+
required: true,
|
|
90
|
+
type: Object
|
|
91
|
+
},
|
|
92
|
+
inDetails: {
|
|
93
|
+
type: Boolean,
|
|
94
|
+
default: false
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
const { locale } = useI18n();
|
|
98
|
+
const { projectButton } = useOipResourceHooks();
|
|
99
|
+
|
|
100
|
+
const dateLang = computed(() => (locale.value === "fr" ? "fr" : "en"));
|
|
101
|
+
|
|
102
|
+
const lastPrice = computed(() => {
|
|
103
|
+
return props.product.jo?.length > 0
|
|
104
|
+
? [...props.product.jo].sort(
|
|
105
|
+
(a: any, b: any) =>
|
|
106
|
+
new Date(b.announce_date).getTime() -
|
|
107
|
+
new Date(a.announce_date).getTime()
|
|
108
|
+
)[0]
|
|
109
|
+
: props.product.jo?.[0];
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
/** Meme formatage monetaire que les cartes du suivi des prix. */
|
|
113
|
+
function money(value: any) {
|
|
114
|
+
if (value === null || value === undefined || value === "" || value === "-") return "NA";
|
|
115
|
+
return new Intl.NumberFormat(locale.value === "en" ? "en-US" : "fr-FR", {
|
|
116
|
+
style: "currency",
|
|
117
|
+
currency: "EUR",
|
|
118
|
+
maximumFractionDigits: 2,
|
|
119
|
+
}).format(Number(value));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const countLabel = computed(() => {
|
|
123
|
+
const count = props.product.jo?.length ?? 0;
|
|
124
|
+
return locale.value === "fr"
|
|
125
|
+
? `${count} publication${count > 1 ? "s" : ""} JO`
|
|
126
|
+
: `${count} JO publication${count > 1 ? "s" : ""}`;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Ce que la roue crantee ne peut pas lire du rendu : l'historique JO complet
|
|
131
|
+
* de la presentation, quand le tableau n'en montre que le tarif courant.
|
|
132
|
+
*/
|
|
133
|
+
const exportPayload = computed(() => ({
|
|
134
|
+
title: `France JO - ${props.product.label}`,
|
|
135
|
+
subtitle: `🇫🇷 JO: ${props.product.label}`,
|
|
136
|
+
limit: 10000,
|
|
137
|
+
sheets: [
|
|
138
|
+
{
|
|
139
|
+
name: locale.value === "fr" ? "Données JO" : "JO Data",
|
|
140
|
+
data: props.product.jo ?? [],
|
|
141
|
+
schema: [
|
|
142
|
+
{ column: locale.value === 'fr' ? 'Code NOR' : 'NOR Code', type: String, value: (a: any) => a.nor_code, width: 20 },
|
|
143
|
+
{ column: locale.value === 'fr' ? 'Code JORF' : 'JORF Code', type: String, value: (a: any) => a.jorf_code, width: 20 },
|
|
144
|
+
{ column: locale.value === 'fr' ? "Date d'application" : 'Application Date', type: Date, format: 'mmm d yyyy', value: (a: any) => new Date(a.application_date), width: 15 },
|
|
145
|
+
{ column: locale.value === 'fr' ? 'PFHT' : 'Ex-Factory Price', type: Number, value: (a: any) => a.factory_price, width: 15 },
|
|
146
|
+
{ column: locale.value === 'fr' ? 'Prix Public' : 'Public Price', type: Number, value: (a: any) => a.public_price, width: 15 },
|
|
147
|
+
{ column: locale.value === 'fr' ? 'Prix TFR' : 'TFR Price', type: Number, value: (a: any) => a.reference_price, width: 15 },
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
}));
|
|
152
|
+
|
|
153
|
+
const buildTable = computed(() => {
|
|
154
|
+
const isCIP = props.product.distribution_channel.includes("CIP");
|
|
155
|
+
return props.inDetails
|
|
156
|
+
? {
|
|
157
|
+
head:
|
|
158
|
+
locale.value === "en"
|
|
159
|
+
? [
|
|
160
|
+
`NOR/JORF Code`,
|
|
161
|
+
"JO Date",
|
|
162
|
+
"Application Date",
|
|
163
|
+
"Ex-Factory Price",
|
|
164
|
+
"Public Price",
|
|
165
|
+
"TFR Price"
|
|
166
|
+
]
|
|
167
|
+
: [
|
|
168
|
+
`Code NORF/JORF`,
|
|
169
|
+
"JO Date",
|
|
170
|
+
"Date d'Application",
|
|
171
|
+
"PFHT",
|
|
172
|
+
"Prix Public",
|
|
173
|
+
"Prix TFR"
|
|
174
|
+
],
|
|
175
|
+
data: props.product?.jo?.map((a: any) => {
|
|
176
|
+
return {
|
|
177
|
+
values: [
|
|
178
|
+
[a.nor_code, a.jorf_code],
|
|
179
|
+
a.announce_date,
|
|
180
|
+
a.application_date,
|
|
181
|
+
a.factory_price,
|
|
182
|
+
a.public_price,
|
|
183
|
+
a.reference_price
|
|
184
|
+
]
|
|
185
|
+
};
|
|
186
|
+
}) ?? [{ values: [] }],
|
|
187
|
+
|
|
188
|
+
type: ["Code", "Date", "Date", "Price", "Price", "Price"],
|
|
189
|
+
style: {
|
|
190
|
+
align: ["left", "left", "left", "right", "right", "right"] as const,
|
|
191
|
+
size: [2, 2, 2, 2, 2, 2]
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
: {
|
|
195
|
+
head:
|
|
196
|
+
locale.value === "en"
|
|
197
|
+
? [
|
|
198
|
+
`${isCIP ? "CIP Code" : "UCD Code"}`,
|
|
199
|
+
"Application Date",
|
|
200
|
+
"Ex-Factory Price",
|
|
201
|
+
"Public Price",
|
|
202
|
+
"TFR Price"
|
|
203
|
+
]
|
|
204
|
+
: [
|
|
205
|
+
`${isCIP ? "Code CIP" : "Code UCD"}`,
|
|
206
|
+
"Date d'Application",
|
|
207
|
+
"PFHT",
|
|
208
|
+
"Prix Public",
|
|
209
|
+
"Prix TFR"
|
|
210
|
+
],
|
|
211
|
+
data: [
|
|
212
|
+
props.product.jo?.map((a: any) => {
|
|
213
|
+
return {
|
|
214
|
+
values: [
|
|
215
|
+
props.product.local_drug_id,
|
|
216
|
+
a.application_date,
|
|
217
|
+
a.factory_price,
|
|
218
|
+
a.public_price,
|
|
219
|
+
a.reference_price
|
|
220
|
+
]
|
|
221
|
+
};
|
|
222
|
+
})?.[0] ?? [{ values: [] }]
|
|
223
|
+
],
|
|
224
|
+
type: ["", "Date", "Price", "Price", "Price"],
|
|
225
|
+
style: {
|
|
226
|
+
align: ["left", "left", "right", "right", "right"] as const,
|
|
227
|
+
size: [3, 3, 2, 2, 2]
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Le tableau du JO etait ecrit pour `arg-table` : des libelles de tete et des
|
|
233
|
+
// lignes `{ values: [...] }`. La conversion en colonnes de RmTable est
|
|
234
|
+
// mecanique, cf. `valueTable`.
|
|
235
|
+
const table = computed(() => {
|
|
236
|
+
const converted = valueTable(
|
|
237
|
+
buildTable.value.head,
|
|
238
|
+
buildTable.value.data,
|
|
239
|
+
buildTable.value.type,
|
|
240
|
+
buildTable.value.style,
|
|
241
|
+
);
|
|
242
|
+
// Une carte de liste ne porte qu'une ligne : ses fleches de tri n'ont rien a
|
|
243
|
+
// trier. La fiche, elle, empile tout l'historique et se trie.
|
|
244
|
+
return props.inDetails
|
|
245
|
+
? converted
|
|
246
|
+
: {
|
|
247
|
+
...converted,
|
|
248
|
+
columns: converted.columns.map((column: any) => ({ ...column, sortable: false })),
|
|
249
|
+
};
|
|
250
|
+
});
|
|
251
|
+
</script>
|
|
252
|
+
|
|
253
|
+
<style scoped>
|
|
254
|
+
.jo_identity {
|
|
255
|
+
display: flex;
|
|
256
|
+
flex-direction: column;
|
|
257
|
+
gap: 2px;
|
|
258
|
+
min-width: 0;
|
|
259
|
+
flex: 1 1 auto;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.jo_meta {
|
|
263
|
+
margin: 0;
|
|
264
|
+
overflow: hidden;
|
|
265
|
+
color: var(--text-secondary);
|
|
266
|
+
font-size: var(--font-13);
|
|
267
|
+
text-overflow: ellipsis;
|
|
268
|
+
white-space: nowrap;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.jo_refs {
|
|
272
|
+
margin: 0;
|
|
273
|
+
color: var(--text-secondary);
|
|
274
|
+
font-size: var(--font-12);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.jo_actions {
|
|
278
|
+
display: flex;
|
|
279
|
+
flex: 0 0 auto;
|
|
280
|
+
align-items: flex-start;
|
|
281
|
+
gap: var(--space-8);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.jo_facts {
|
|
285
|
+
display: flex;
|
|
286
|
+
flex: 0 0 auto;
|
|
287
|
+
flex-direction: column;
|
|
288
|
+
align-items: flex-end;
|
|
289
|
+
gap: 2px;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* Meme pastille que le compte de presentations des cartes de marque. */
|
|
293
|
+
.jo_count {
|
|
294
|
+
padding: var(--space-2) var(--space-8);
|
|
295
|
+
border-radius: 999px;
|
|
296
|
+
background: color-mix(in srgb, var(--color-primary) 8%, transparent);
|
|
297
|
+
color: var(--color-primary);
|
|
298
|
+
font-size: var(--font-12);
|
|
299
|
+
font-weight: 700;
|
|
300
|
+
white-space: nowrap;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.jo_date {
|
|
304
|
+
color: var(--text-secondary);
|
|
305
|
+
font-size: var(--font-12);
|
|
306
|
+
white-space: nowrap;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.jo_footer {
|
|
310
|
+
border-top: 1px solid var(--border-default);
|
|
311
|
+
background: var(--bg-surface-2);
|
|
312
|
+
font-size: var(--font-13);
|
|
313
|
+
}
|
|
314
|
+
</style>
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span class="oip-drugs" :class="haveReadMore && needsMore ? 'crop_display' : ''">
|
|
3
|
+
<span
|
|
4
|
+
:id="id"
|
|
5
|
+
:class="crop && !showMore ? 'crop' : ''"
|
|
6
|
+
:style="crop && !showMore ? `-webkit-line-clamp: ${lines}` : ''"
|
|
7
|
+
v-html="renderText"
|
|
8
|
+
/>
|
|
9
|
+
<div
|
|
10
|
+
v-if="crop && haveReadMore && needsMore"
|
|
11
|
+
@click="toggleMore"
|
|
12
|
+
class="read_more"
|
|
13
|
+
>
|
|
14
|
+
{{ getReadMore }}
|
|
15
|
+
</div>
|
|
16
|
+
</span>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
export default defineComponent({
|
|
21
|
+
name: "heartTextHighlight",
|
|
22
|
+
props: {
|
|
23
|
+
text: {
|
|
24
|
+
type: String,
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
queries: {
|
|
28
|
+
type: Array as PropType<string[]>,
|
|
29
|
+
default: null,
|
|
30
|
+
},
|
|
31
|
+
genes: {
|
|
32
|
+
type: Array as PropType<any[]>,
|
|
33
|
+
default: null,
|
|
34
|
+
},
|
|
35
|
+
crop: {
|
|
36
|
+
type: Boolean,
|
|
37
|
+
default: false,
|
|
38
|
+
},
|
|
39
|
+
lines: {
|
|
40
|
+
type: Number,
|
|
41
|
+
default: 3,
|
|
42
|
+
},
|
|
43
|
+
haveReadMore: {
|
|
44
|
+
type: Boolean,
|
|
45
|
+
default: false,
|
|
46
|
+
},
|
|
47
|
+
id: {
|
|
48
|
+
type: String,
|
|
49
|
+
default: null,
|
|
50
|
+
},
|
|
51
|
+
customReadMore: {
|
|
52
|
+
type: Object as () => { more: string; less: string },
|
|
53
|
+
default: null,
|
|
54
|
+
},
|
|
55
|
+
/**
|
|
56
|
+
* Surlignage des pages d'indication (LES) : fr_drugs_app le lisait dans
|
|
57
|
+
* le chemin (`/indication`), le layer le recoit en prop.
|
|
58
|
+
*/
|
|
59
|
+
indication: {
|
|
60
|
+
type: Boolean,
|
|
61
|
+
default: undefined,
|
|
62
|
+
},
|
|
63
|
+
lang: {
|
|
64
|
+
type: String as () => "en" | "fr" | "es",
|
|
65
|
+
default: "en",
|
|
66
|
+
validator: (value: string) => {
|
|
67
|
+
return ["en", "fr", "es"].includes(value);
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
emits: ["onShowMore", "onShowLess"],
|
|
72
|
+
setup(props, { emit }) {
|
|
73
|
+
// Sous une fiche indication (cf. IndicationFiche), sans prop explicite.
|
|
74
|
+
const indicationPage = inject<boolean>("oipDrugsIndicationPage", false);
|
|
75
|
+
const showMore = ref(false);
|
|
76
|
+
const indic = ref<HTMLElement | null>(null);
|
|
77
|
+
|
|
78
|
+
const getReadMore = computed(() => {
|
|
79
|
+
if (props.customReadMore !== null) {
|
|
80
|
+
return showMore.value
|
|
81
|
+
? props.customReadMore.less
|
|
82
|
+
: props.customReadMore.more;
|
|
83
|
+
} else {
|
|
84
|
+
const texts = {
|
|
85
|
+
more: { en: "Read more", fr: "Voir plus", es: "Ver más" },
|
|
86
|
+
less: { en: "Read less", fr: "Voir moins", es: "Ver menos" },
|
|
87
|
+
};
|
|
88
|
+
return showMore.value ? texts.less[props.lang] : texts.more[props.lang];
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
function removeAccents(str: string): string {
|
|
93
|
+
return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function addSingleAccent(
|
|
97
|
+
word: string,
|
|
98
|
+
char: string,
|
|
99
|
+
accentedChar: string
|
|
100
|
+
): string[] {
|
|
101
|
+
let variants: string[] = [];
|
|
102
|
+
for (let i = 0; i < word.length; i++) {
|
|
103
|
+
if (word[i]!.toLowerCase() === char) {
|
|
104
|
+
variants.push(word.slice(0, i) + accentedChar + word.slice(i + 1));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return variants;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function addAccents(word: string): string[] {
|
|
111
|
+
let variants: string[] = [word];
|
|
112
|
+
if (!word.toLowerCase().includes("é")) {
|
|
113
|
+
variants = variants.concat(addSingleAccent(word, "e", "é"));
|
|
114
|
+
}
|
|
115
|
+
if (!word.toLowerCase().includes("ï")) {
|
|
116
|
+
variants = variants.concat(addSingleAccent(word, "i", "ï"));
|
|
117
|
+
}
|
|
118
|
+
return variants;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function handleEndingS(word: string): string[] {
|
|
122
|
+
let variants: string[] = [word];
|
|
123
|
+
if (word.toLowerCase().endsWith("s")) {
|
|
124
|
+
variants.push(word.slice(0, -1));
|
|
125
|
+
} else {
|
|
126
|
+
variants.push(word + "s");
|
|
127
|
+
}
|
|
128
|
+
return variants;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function capitalizeFirstLetter(str: string): string {
|
|
132
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Les termes arrivent sous deux formes selon la barre de recherche qui les
|
|
137
|
+
* a produits : une chaine, ou un operateur `{ type, value }`. On ramene
|
|
138
|
+
* tout a des mots, et on ecarte les termes exclus — surligner ce que
|
|
139
|
+
* l'utilisateur a demande d'exclure n'aurait pas de sens.
|
|
140
|
+
*/
|
|
141
|
+
function toWords(arr: any[]): string[] {
|
|
142
|
+
return (arr ?? [])
|
|
143
|
+
.filter((item) => item !== null && item !== undefined)
|
|
144
|
+
.filter((item) => typeof item !== "object" || item.type !== "not")
|
|
145
|
+
.map((item) => (typeof item === "object" ? item.value : item))
|
|
146
|
+
.filter((value): value is string => typeof value === "string" && value.trim() !== "")
|
|
147
|
+
// Une recherche a plusieurs mots est une phrase avec slop, ou un ET
|
|
148
|
+
// flou : les mots matchent separes (« cancer … de l’ovaire »). On
|
|
149
|
+
// les surligne donc un par un, sans les mots-outils (« de », « la »).
|
|
150
|
+
.flatMap((value) => {
|
|
151
|
+
const words = value.trim().split(/\s+/);
|
|
152
|
+
return words.length > 1 ? words.filter((word) => word.length >= 3) : words;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function processArray(input: any[]): string[] {
|
|
157
|
+
let result: string[] = [];
|
|
158
|
+
const arr = toWords(input);
|
|
159
|
+
|
|
160
|
+
if (arr !== null && arr.length > 0) {
|
|
161
|
+
arr.forEach((word) => {
|
|
162
|
+
// Add original word
|
|
163
|
+
result.push(word);
|
|
164
|
+
|
|
165
|
+
// Handle accents removal
|
|
166
|
+
const wordWithoutAccents = removeAccents(word);
|
|
167
|
+
if (word !== wordWithoutAccents) {
|
|
168
|
+
result.push(wordWithoutAccents);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Handle adding accents to e and i if no accents already exist
|
|
172
|
+
const accentedVariants = addAccents(word);
|
|
173
|
+
accentedVariants.forEach((accentedWord) => {
|
|
174
|
+
result.push(accentedWord);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Handle ending s for original word, word without accents, and accented variants
|
|
178
|
+
const wordsToProcess = [
|
|
179
|
+
word,
|
|
180
|
+
wordWithoutAccents,
|
|
181
|
+
...accentedVariants,
|
|
182
|
+
];
|
|
183
|
+
wordsToProcess.forEach((w) => {
|
|
184
|
+
const sVariants = handleEndingS(w);
|
|
185
|
+
sVariants.forEach((sVariant) => {
|
|
186
|
+
if (!result.includes(sVariant)) {
|
|
187
|
+
result.push(sVariant);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Add uppercase variants of each processed word
|
|
193
|
+
const processedWords = [...result];
|
|
194
|
+
processedWords.forEach((w) => {
|
|
195
|
+
const capitalized = capitalizeFirstLetter(w);
|
|
196
|
+
if (!result.includes(capitalized)) {
|
|
197
|
+
result.push(capitalized);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function toggleMore() {
|
|
207
|
+
showMore.value = !showMore.value;
|
|
208
|
+
|
|
209
|
+
if (showMore.value) {
|
|
210
|
+
emit("onShowMore");
|
|
211
|
+
} else {
|
|
212
|
+
emit("onShowLess");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function escapeRegExp(str: string) {
|
|
217
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const HTML_ESCAPES: Record<string, string> = {
|
|
221
|
+
"&": "&",
|
|
222
|
+
"<": "<",
|
|
223
|
+
">": ">",
|
|
224
|
+
'"': """,
|
|
225
|
+
"'": "'",
|
|
226
|
+
};
|
|
227
|
+
function escapeHtml(str: string) {
|
|
228
|
+
return str.replace(/[&<>"']/g, (c) => HTML_ESCAPES[c] ?? c);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Le texte part dans un `v-html` : il vient d'Elasticsearch brut, on
|
|
233
|
+
* l'echappe. Seul prefixe HTML tolere : le statut d'avis que la carte
|
|
234
|
+
* d'acces precoce colle devant l'essentiel (`has_fav_access` /
|
|
235
|
+
* `has_defav_access`), rendu tel quel et laisse hors du surlignage.
|
|
236
|
+
*/
|
|
237
|
+
const STATUS_PREFIX = /^<span class="has_(?:de)?fav_access">[^<]*<\/span>/;
|
|
238
|
+
|
|
239
|
+
const needsMore = computed(() => {
|
|
240
|
+
const fullHeight = ref(0);
|
|
241
|
+
const originalHeight = ref(0);
|
|
242
|
+
|
|
243
|
+
if (indic.value !== null) {
|
|
244
|
+
indic.value.classList.remove("crop");
|
|
245
|
+
|
|
246
|
+
fullHeight.value = indic.value.offsetHeight;
|
|
247
|
+
indic.value.classList.add("crop");
|
|
248
|
+
originalHeight.value = indic.value.offsetHeight;
|
|
249
|
+
}
|
|
250
|
+
return fullHeight.value > originalHeight.value;
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const renderText = computed(() => {
|
|
254
|
+
const prefix = STATUS_PREFIX.exec(props.text ?? "")?.[0] ?? "";
|
|
255
|
+
let returnText = escapeHtml((props.text ?? "").slice(prefix.length));
|
|
256
|
+
|
|
257
|
+
if (props.queries !== null && props.queries.length > 0) {
|
|
258
|
+
const sepQueries = props.queries;
|
|
259
|
+
// Les termes sont echappes comme le texte, pour se retrouver dedans.
|
|
260
|
+
const queries = processArray(sepQueries)
|
|
261
|
+
.filter((query) => query.trim() !== "")
|
|
262
|
+
.map((query) => escapeRegExp(escapeHtml(query)));
|
|
263
|
+
|
|
264
|
+
// Plus rien a surligner (que des termes exclus, par exemple) : une
|
|
265
|
+
// alternation vide matcherait chaque position du texte.
|
|
266
|
+
if (queries.length === 0) return prefix + returnText;
|
|
267
|
+
|
|
268
|
+
// Create a single regex to match any of the queries, case-insensitive.
|
|
269
|
+
// `$` : un terme en toute fin de texte se surligne aussi.
|
|
270
|
+
const regex = new RegExp(
|
|
271
|
+
(props.indication ?? indicationPage)
|
|
272
|
+
? `\\b(${queries.join("|")})(?=\\s|\\d|\\W|\\w|\\b)`
|
|
273
|
+
: `\\b(${queries.join("|")})(?=[s\\d\\W]|$)`,
|
|
274
|
+
"gi" // case-insensitive matching
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
returnText = returnText.replace(regex, (match) => {
|
|
278
|
+
return `<mark>${match}</mark>`;
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return prefix + returnText;
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
onMounted(() => {
|
|
286
|
+
indic.value = document.getElementById(props.id);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
showMore,
|
|
291
|
+
needsMore,
|
|
292
|
+
renderText,
|
|
293
|
+
getReadMore,
|
|
294
|
+
toggleMore,
|
|
295
|
+
};
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
</script>
|
|
299
|
+
|
|
300
|
+
<style scoped>
|
|
301
|
+
.crop {
|
|
302
|
+
display: -webkit-box;
|
|
303
|
+
-webkit-box-orient: vertical;
|
|
304
|
+
overflow: hidden;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.crop_display {
|
|
308
|
+
display: flex;
|
|
309
|
+
flex-direction: column;
|
|
310
|
+
gap: 8px;
|
|
311
|
+
align-items: flex-start;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.read_more {
|
|
315
|
+
font-size: 14px;
|
|
316
|
+
font-style: normal;
|
|
317
|
+
font-weight: 500;
|
|
318
|
+
line-height: normal;
|
|
319
|
+
text-decoration-line: underline;
|
|
320
|
+
cursor: pointer;
|
|
321
|
+
color: var(--primary);
|
|
322
|
+
}
|
|
323
|
+
.read_more:hover {
|
|
324
|
+
color: var(--primary-hover) !important;
|
|
325
|
+
}
|
|
326
|
+
</style>
|