Skip to content

Commit

Permalink
Use context of view component to show tooltip only on first occurrenc…
Browse files Browse the repository at this point in the history
…e of a term
  • Loading branch information
ksuess committed Oct 11, 2024
1 parent 53238a4 commit a95bc48
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 61 deletions.
25 changes: 13 additions & 12 deletions .release-it.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
{
"github": {
"release": true
"npm": {
"publish": true
},
"git": {
"commitMessage": "chore: release ${version}"
"changelog": "npx auto-changelog --stdout --commit-limit false -u --template https://raw.githubusercontent.com/release-it/release-it/master/templates/changelog-compact.hbs",
"tagName": "${version}"
},
"github": {
"release": true,
"releaseName": "${version}",
"releaseNotes": "npx auto-changelog --stdout --commit-limit false -u --template https://raw.githubusercontent.com/release-it/release-it/master/templates/changelog-compact.hbs"
},
"plugins": {
"@release-it/conventional-changelog": {
"infile": "CHANGELOG.md",
"header": "# Changelog",
"preset": {
"name": "conventionalcommits"
}
}
"hooks": {
"before:init": "",
"after:bump": "npx auto-changelog --commit-limit false -p"
}
}
}
52 changes: 34 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,31 @@ Volto Add-On `@rohberg/volto-slate-glossary` adds tooltips for glossary terms of

![Tooltips @rohberg/volto-slate-glossary](https://github.com/rohberg/volto-slate-glossary/raw/main/public/volto-slate-glossary-tooltips.png)

Determine where to apply tooltips in your project by match configuration:

import { Tooltips } from '@rohberg/volto-slate-glossary/components';
Install Plone Add-On [collective.glossary](https://github.com/collective/collective.glossary) in your backend.

export default function applyConfig(config) {
config.settings.appExtras = [
...config.settings.appExtras,
{
match: '/documentation',
component: Tooltips,
},
{
match: '/news',
component: Tooltips,
},
];

return config;
}
Determine where to apply tooltips in your project by match configuration:

```javascript
import { Tooltips } from '@rohberg/volto-slate-glossary/components';

export default function applyConfig(config) {
config.settings.appExtras = [
...config.settings.appExtras,
{
match: '/documentation',
component: Tooltips,
},
{
match: '/news',
component: Tooltips,
},
];

return config;
}
```

By default we show a tooltip when a word matches case insensitively: when the term is "Hello" or "hello", a tooltip is shown for "Hello", "hello", "HELLO", "hElLo", etcetera.

Expand All @@ -34,11 +40,21 @@ config.settings.glossary.caseSensitive = true;

Regardless of this setting, when you have a fully uppercase term, for example `REST` (Representational State Transfer), always only the exact word `REST` gets a tooltip, not `rest` or `Rest`.

Install Plone Add-On [collective.glossary](https://github.com/collective/collective.glossary) in your backend.
By default we show tooltips for all occurences of a term.

Since version 2.0.0 you can configure to only show tooltips for the first occurence on a page.

```js
config.settings.glossary.matchOnlyFirstOccurence = true;
```

User can opt-out by setting glossarytooltips to false.
Add a boolean member field *glossarytooltips* for it.


This add-on requires Volto with Slate editor. Be sure to upgrade to Volto >= 16.0.0-alpha.15.
## Compatibility

| volto-slate-glossary version | Volto version |
|-------------|---------------|
| 1.x.x | >= Volto 16.0.0-alpha.15 |
| 2.x.x | >= Volto 18.0.0-alpha.48 |
20 changes: 15 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,27 @@
"version": "1.0.3",
"description": "Add tooltips for glossary terms",
"main": "src/index.js",
"author": "Katja Süss, https://github.com/rohberg",
"license": "MIT",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"homepage": "https://github.com/rohberg/volto-slate-glossary",
"keywords": [
"volto-addon",
"volto",
"plone",
"react"
"react",
"glossary"
],
"repository": {
"type": "git",
"url": "[email protected]:rohberg/volto-slate-glossary.git"
},
"bugs": {
"url": "https://github.com/rohberg/volto-slate-glossary/issues"
},
"scripts": {
"i18n": "rm -rf build/messages && NODE_ENV=production i18n --addon",
"release": "release-it"
Expand All @@ -18,10 +32,6 @@
"dependencies": {
"@plone/scripts": "*"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"devDependencies": {
"@release-it/conventional-changelog": "^8.0.2",
"release-it": "^17.6.0"
Expand Down
33 changes: 16 additions & 17 deletions src/components/glossarytooltips.less
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
.glossarytooltip {
cursor: help;
border-bottom: 2px dotted #963c38;
cursor: help;
border-bottom: 2px dotted #963c38;
}
.ui.popup {
hyphens: auto;
font-size: 75% !important;
ol {
padding-left: 1rem;
}
hyphens: auto;
font-size: 75% !important;
ol {
padding-left: 1rem;
}
}

.hidden-helper {
display: none;
display: none;
}


// Glossar
.glossary h2.letter {
background: #963c38;
color: white;
margin: 2rem 0 1rem;
padding: 0.3em .5em;
background: #963c38;
color: white;
margin: 2rem 0 1rem;
padding: 0.3em 0.5em;
}
.term h3 {
span {
font-size: 80%;
}
}
span {
font-size: 80%;
}
}
5 changes: 5 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ import { TextWithGlossaryTooltips } from './utils';
export default (config) => {
config.settings.glossary = {
caseSensitive: false,
matchOnlyFirstOccurence: false,
};

config.views.viewContext['volto-slate-glossary'] = [];

config.settings.slate.leafs = {
text: ({ children }) => <TextWithGlossaryTooltips text={children} />,
};

config.views = {
...config.views,
contentTypesViews: {
Expand Down
41 changes: 32 additions & 9 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import config from '@plone/volto/registry';
import { useSelector } from 'react-redux';
import { flatten } from 'lodash';
import { Popup } from 'semantic-ui-react';
import { useLocation } from 'react-router-dom';

import { useViewContext } from '@plone/volto/components/theme/View/View';
import config from '@plone/volto/registry';

/**
* import from @plone/volto-slate Leaf when ready there
Expand Down Expand Up @@ -36,26 +36,36 @@ const applyLineBreakSupport = (children) => {

export const TextWithGlossaryTooltips = ({ text }) => {
const caseSensitive = config.settings.glossary.caseSensitive;
const matchOnlyFirstOccurence =
config.settings.glossary.matchOnlyFirstOccurence;
const glossaryterms = useSelector(
(state) => state.glossarytooltipterms?.result?.items,
);
const location = useLocation();

// no tooltips if user opted out
// No tooltips if user opted out
const currentuser = useSelector((state) => state.users?.user);
const glossarytooltips = currentuser?.glossarytooltips ?? true;
if (!glossarytooltips) {
return text;
}
// No tooltips in edit and add mode
const isEditMode = location.pathname.slice(-5) === '/edit';
const isAddMode = location.pathname.slice(-4) === '/add';
if (isEditMode || isAddMode || location.pathname === '/' || !__CLIENT__) {
return text;
}

let matchedGlossaryTerms = useViewContext('volto-slate-glossary');

let result = [{ type: 'text', val: text }];
if (glossaryterms !== undefined) {
glossaryterms.forEach((term) => {
let remainingGlossaryterms = matchOnlyFirstOccurence
? glossaryterms.filter(
(term) => !matchedGlossaryTerms.includes(term.term),
)
: glossaryterms;
remainingGlossaryterms.forEach((term) => {
result = result.map((chunk) => {
if (chunk.type === 'text') {
let new_chunk = [];
Expand All @@ -68,21 +78,32 @@ export const TextWithGlossaryTooltips = ({ text }) => {
let myre = `(?<!\\p{L})(${term.term})(?!\\p{L})`;
if (caseSensitive || term.term === term.term.toUpperCase()) {
// Search case sensitively: if term is 'REST', we don't want to highlight 'rest'.
regExpTerm = RegExp(myre, "gv");
regExpTerm = RegExp(myre, 'gv');
} else {
// Search case insensitively.
regExpTerm = RegExp(myre, "giv");
regExpTerm = RegExp(myre, 'giv');
}
let chunk_val = chunk.val;
let index = 0;
while (true) {
let res = regExpTerm.exec(chunk.val);
if (res === null) {
if (
res === null ||
(matchOnlyFirstOccurence &&
matchedGlossaryTerms.includes(term.term))
) {
new_chunk.push({ type: 'text', val: chunk_val.slice(index) });
break;
}
// Term matched. Update context!
if (matchOnlyFirstOccurence) {
matchedGlossaryTerms.push(term.term);
}
if (res.index > 0) {
new_chunk.push({ type: 'text', val: chunk_val.slice(index, res.index) });
new_chunk.push({
type: 'text',
val: chunk_val.slice(index, res.index),
});
}
new_chunk.push({
type: 'glossarytermtooltip',
Expand All @@ -103,7 +124,9 @@ export const TextWithGlossaryTooltips = ({ text }) => {
if (el.type === 'text') {
return applyLineBreakSupport(el.val);
} else {
let idx = glossaryterms.findIndex((variant) => variant.term.toLowerCase() === el.val.toLowerCase());
let idx = glossaryterms.findIndex(
(variant) => variant.term.toLowerCase() === el.val.toLowerCase(),
);
let definition = glossaryterms[idx]?.definition || '';
switch (definition.length) {
case 0:
Expand Down

0 comments on commit a95bc48

Please sign in to comment.