Commit 21a4f3b9 authored by dindigala's avatar dindigala
Browse files

chore: merge branch 'develop' into feat/#318-text-scroll-into-view

parents fa686eb7 9eef247e
Pipeline #222005 passed with stages
in 3 minutes and 9 seconds
......@@ -212,6 +212,8 @@ export default {
this.currentTab = key;
this.highlightActiveContent(this.filteredAnnotations);
this.handleTooltip();
},
addAnnotation(annotation) {
......@@ -239,6 +241,17 @@ export default {
addIcon(element, annotation) {
const contentType = annotation.body['x-content-type'];
let foundSvg = false;
[...element.children].forEach((el) => {
if (el.nodeName === 'svg' && el.getAttribute('data-annotation-icon')) {
foundSvg = true;
}
});
if (foundSvg) {
return;
}
try {
const svg = this.createSVG(this.getIconName(contentType));
svg.setAttribute(
......@@ -272,16 +285,6 @@ export default {
return svg;
},
onContentUpdate(ids) {
try {
this.currentTab = this.annotationTabs[0].key;
this.contentIds = ids;
this.highlightActiveContent(this.filteredAnnotations);
} catch (err) {
setTimeout(() => this.onContentUpdate(ids), 100);
}
},
getIcon(contentType) {
return Icons[this.getIconName(contentType)];
},
......@@ -292,6 +295,77 @@ export default {
)[0].icon;
},
getTooltipId(el) {
return `${el.className.split(' ').join('')}annotation-tooltip`;
},
handleTooltip() {
const annotationIds = this.filteredAnnotations.reduce((prev, curr) => {
let id = this.stripTargetId(curr, false);
if (id.startsWith('.')) {
id = id.replace('.', '');
}
prev[id] = {
value: curr.body.value,
contentType: curr.body['x-content-type'],
};
return prev;
}, {});
document.querySelectorAll('[data-annotation]').forEach((el) => {
const childOtherNodes = [...el.childNodes].filter((x) => x.nodeName !== '#text').length;
if (!childOtherNodes) {
const classNames = [];
el = this.backTrackNestedAnnotations(el, classNames);
const annotationClasses = [];
// checks for duplicate class names.
classNames
.join(' ')
.split(' ')
.map((x) => annotationIds[x])
.filter((x) => x)
.reduce((prev, curr) => {
if (!prev[curr.value]) {
prev[curr.value] = true;
annotationClasses.push(curr);
}
return prev;
}, {});
if (annotationClasses.length) {
el.addEventListener('mouseenter', () => this.onMouseHover(el, annotationClasses), false);
el.addEventListener('mouseout', () => this.onMouseOut(), false);
}
}
});
},
backTrackNestedAnnotations(el, classNames = []) {
let current = el;
while (current.parentElement.getAttribute('data-annotation') && current.parentElement.childNodes.length === 1) {
classNames.push(current.className);
current = current.parentElement;
}
return el;
},
onContentUpdate(ids) {
try {
this.currentTab = this.annotationTabs[0].key;
this.contentIds = ids;
this.highlightActiveContent(this.filteredAnnotations);
this.handleTooltip();
} catch (err) {
setTimeout(() => this.onContentUpdate(ids), 100);
}
},
onHighlightAll() {
this.filteredAnnotations.forEach(
(annotation) => !this.activeAnnotation[annotation.targetId]
......@@ -306,6 +380,70 @@ export default {
);
},
onMouseHover(el, annotationClasses) {
const queue = [];
// this logic checks the child spans and classes.
queue.push(el);
let matched = false;
while (queue.length) {
const popped = queue.pop();
if (parseInt(popped.getAttribute('data-annotation-level'), 10) > 0) {
matched = true;
} else {
[...popped.children].forEach((child) => {
queue.push(child);
});
}
}
if (!el || !matched) {
return;
}
const tooltipEl = document.createElement('span');
tooltipEl.setAttribute('data-annotation-classes', `${el.className}`);
tooltipEl.setAttribute('class', 'annotation-tooltip');
const isMultiple = annotationClasses.length > 1;
let annotationLists = '';
annotationClasses.forEach((annotationList) => {
annotationLists += `<div class="referenced-annotation">
${this.createSVG(this.getIconName(annotationList.contentType)).outerHTML}
<span>
${annotationList.value}
</span>
</div>`;
});
const text = `<span class="text-body1">
${!isMultiple ? `${this.$t('toolTip_Reference')}` : `${this.$t('toolTip_References')}`}:
</span>
<br>
<div class="text-body2">
${annotationLists}
</div>`;
tooltipEl.innerHTML = text;
tooltipEl.setAttribute('id', this.getTooltipId(el));
window.top.el = el;
const r = el.getBoundingClientRect();
tooltipEl.style.top = `${r.y + r.height}px`;
tooltipEl.style.left = `${r.x}px`;
document.querySelector('body').append(tooltipEl);
setTimeout(() => tooltipEl.classList.add('annotation-animated-tooltip'), 10);
},
onMouseOut() {
[...document.querySelectorAll('.annotation-tooltip')].forEach((x) => x.remove());
},
removeIcon(annotation) {
const stripeId = this.stripTargetId(annotation);
const el = document
......@@ -392,6 +530,44 @@ export default {
background-color: $blue-5;
border-bottom: 1px solid #000;
}
.annotation-tooltip {
background-color: $grey-2 !important;
box-shadow: $shadow-1;
color: #000 !important;
font-size: 14px;
left: 0;
opacity: 0;
padding: 8px;
position: absolute;
text-decoration: none !important;
top: 0;
transition: opacity 0.5s;
width: 240px;
z-index: 10000;
}
.annotation-tooltip {
-webkit-touch-callout: none;
}
.annotation-animated-tooltip {
opacity: 1;
}
.referenced-annotation {
display: block;
margin-bottom: 4px;
}
.referenced-annotation:first-of-type {
padding-top: 4px;
}
.referenced-annotation:last-of-type {
margin-bottom: 0;
}
</style>
<style lang="scss" scoped>
......
......@@ -34,7 +34,7 @@
>
<a
:class="$q.dark.isActive ? 'text-dark' : 'text-white'"
:href="`${redirectUrl}?searchTerm=${searchTerm}`"
:href="`${redirectUrl}search.html?searchTerm=${searchTerm}`"
class="header-links"
>
<q-icon
......
......@@ -138,7 +138,7 @@ export default {
let dom = parser.parseFromString(data, 'text/html');
if (!annotationPanelHidden) {
const spans = [
...dom.querySelectorAll('span[data-target]:not([value=""])'),
...dom.querySelectorAll('[data-target]:not([value=""])'),
];
const spanIds = [
......
......@@ -5,10 +5,11 @@
:class="$q.dark.isActive ? 'bg-white' : 'bg-accent'"
>
<BreadCrumbNavigation
v-if="$route.query.source==='external'"
v-if="$route.query.source === 'external'"
:config="config"
/>
</div>
<div class="header__wrap">
<q-toolbar v-if="config['header_section'].titles">
<TitleBar
......@@ -30,10 +31,10 @@
<q-toolbar class="q-pb-sm">
<Navbar
v-if="config['header_section'].navigation"
:default-view="defaultView"
:itemurls="itemurls"
:labels="config.labels"
:manifests="manifests"
:default-view="defaultView"
/>
<q-space />
......@@ -59,8 +60,8 @@
</template>
<script>
import Navbar from '@/components/navbar.vue';
import BreadCrumbNavigation from '@/components/breadcrumbnavigation.vue';
import Navbar from '@/components/navbar.vue';
import TitleBar from '@/components/titlebar.vue';
import TogglePanels from '@/components/togglebar/togglePanels.vue';
import Tools from '@/components/tools.vue';
......@@ -68,17 +69,13 @@ import Tools from '@/components/tools.vue';
export default {
name: 'Header',
components: {
BreadCrumbNavigation,
Navbar,
TitleBar,
TogglePanels,
BreadCrumbNavigation,
Tools,
},
props: {
defaultView: {
type: Function,
default: () => {},
},
collectiontitle: {
type: String,
default: () => '',
......@@ -87,6 +84,10 @@ export default {
type: Object,
default: () => {},
},
defaultView: {
type: Function,
default: () => {},
},
imageurl: {
type: String,
default: () => '',
......
<template>
<div>
<h1 class="text-h5 text-bold text-uppercase q-mb-none q-mt-xs">
{{ ahiqar ? $t('cTitle') : collectiontitle }}
<h1
v-if="collectiontitle"
class="text-h5 text-bold text-uppercase q-mb-none q-mt-xs"
>
{{ collectiontitle }}
</h1>
<h2 class="text-h6 text-bold text-uppercase q-mt-none q-mb-none">
<span>{{ manifesttitle }}</span>
<q-icon
class="q-pb-xs q-pl-sm q-pr-sm"
size="xs"
:color="$q.dark.isActive ? 'white' : 'accent'"
:name="fasChevronRight"
/>
<span>{{ $t('Sheet') }} {{ item.n }}</span>
</h2>
</div>
......@@ -37,7 +43,6 @@ export default {
},
data() {
return {
ahiqar: true,
sequenceindex: 0,
};
},
......
......@@ -7,7 +7,6 @@ export default {
colorScheme: 'Farbschema ändern',
Contents: 'Inhalt',
contentsMetadata: 'Inhalt & Metadaten',
cTitle: 'Die Geschichte und Redewendungen von Ahikar dem Weisen',
'Current location': 'Aktueller Standort',
'Date of creation': 'Erstelldatum',
Decrease: 'Verkleinern',
......@@ -58,6 +57,8 @@ export default {
Title: 'Titel',
title_homepage: 'Die syrischen und arabischen Ahiqar-Texte',
title_viewer: 'Edition anzeigen',
toolTip_Reference: 'Referenzierte Annotation',
toolTip_References: 'Referenzierte Annotationen',
transcription: 'Transkription',
transliteration: 'Transliteration',
Year: 'Erstellungsjahr',
......
......@@ -7,7 +7,6 @@ export default {
colorScheme: 'Change color',
Contents: 'Contents',
contentsMetadata: 'Contents & Metadata',
cTitle: 'The Story and Proverbs of Ahiqar the Wise',
'Current location': 'Current location',
'Date of creation': 'Date of creation',
Decrease: 'Decrease',
......@@ -58,6 +57,8 @@ export default {
Title: 'Title',
title_homepage: 'The Syriac, Arabic, and Karshuni Ahiqar Texts',
title_viewer: 'Edition Viewer',
toolTip_Reference: 'Referenced Annotation',
toolTip_References: 'Referenced Annotations',
transcription: 'Transcription',
transliteration: 'Transliteration',
Year: 'Year of creation',
......
......@@ -3,17 +3,23 @@ export default {
getAllElementsFromSelector(selector, arr = []) {
const el = document.getElementById(selector);
if (el) {
arr.push(el);
// https://www.geeksforgeeks.org/queue-data-structure/
const queue = [];
[...el.children].forEach((child) => {
arr.push(child);
queue.push(el);
while (queue.length) {
const popped = queue.pop();
arr.push(popped);
[...popped.children].forEach((child) => {
queue.push(child);
});
}
return arr;
}
return [...document.querySelectorAll(`.${selector}`)];
},
getElementById(id) {
if (!id) {
return null;
......@@ -81,8 +87,8 @@ export default {
},
replaceSelectorWithSpan(selector, root) {
const start = root.querySelector(`span[data-target="${selector}_start"]`);
const end = root.querySelector(`span[data-target="${selector}_end"]`);
const start = root.querySelector(`[data-target="${selector}_start"]`);
const end = root.querySelector(`[data-target="${selector}_end"]`);
let started = false;
let ended = false;
......@@ -184,8 +190,9 @@ export default {
stripSelector(annotation) {
return `.${annotation.target.selector.startSelector.value
.replace("span[data-target='", '')
.replace("_start']", '')
.replace("_end']", '')}`;
.replace("'", '')
.replace('_start]', '')
.replace('_end]', '')}`;
},
stripTargetId(annotation, removeDot = true) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment