Commit 61d3cd4b authored by dindigala's avatar dindigala
Browse files

chore: merge 'develop' into feature/#237-annotation-links

parents 385244db 3c631299
Pipeline #200080 passed with stages
in 2 minutes and 8 seconds
......@@ -20,6 +20,7 @@
<q-page-container class="root">
<router-view
:annotations="annotations"
:annotation-loading="annotationLoading"
:collection="collection"
:config="config"
:contenttypes="contentTypes"
......@@ -51,6 +52,7 @@ export default {
data() {
return {
annotations: [],
annotationLoading: false,
collection: {},
collectiontitle: '',
config: {},
......@@ -132,6 +134,9 @@ export default {
* @param string url
*/
async getAnnotations(url) {
this.annotations = [];
this.annotationLoading = false;
try {
const annotations = await this.request(url);
......@@ -150,6 +155,8 @@ export default {
} catch (err) {
this.annotations = [];
this.$q.notify({ message: 'No annotations available' });
} finally {
this.annotationLoading = true;
}
},
/**
......
......@@ -5,14 +5,22 @@
>
<q-list>
<q-item
v-for="annotation in filterAnnotationTypes(annotations)"
v-for="annotation in types"
:id="'list' + stripAnnotationId(annotation.target.id)"
:key="stripAnnotationId(annotation.id)"
clickable
padding="xs"
class="q-pa-sm q-pl-xs q-mb-xs"
@click="toggle(stripAnnotationId(annotation.target.id))"
>
<q-item-section avatar>
<q-icon :name="getIcon(annotation.body['x-content-type'])" />
<q-item-section
avatar
class="q-mr-none"
>
<q-icon
:name="getIcon(annotation.body['x-content-type'])"
size="16px"
/>
</q-item-section>
<q-item-section>
......@@ -22,25 +30,34 @@
</q-list>
</div>
<div v-else>
<p>One does not simply show annotations.</p>
<div
v-else
class="q-pa-sm"
>
<Notification :message="$t(messages.none)" />
</div>
</template>
<script>
import * as Icons from '@quasar/extras/fontawesome-v5';
import AnnotationUrls from '@/components/urls.vue';
import Notification from '@/components/notification.vue';
export default {
name: 'Annotations',
components: {
AnnotationUrls,
Notification,
},
props: {
annotations: {
type: Array,
default: () => [],
},
annotationLoading: {
type: Boolean,
default: false,
},
config: {
type: Object,
default: () => {},
......@@ -48,27 +65,35 @@ export default {
},
data() {
return {
messages: {
none: 'noAnnotationMessage',
},
ids: [],
types: [],
};
},
computed: {
configuredTypes() {
const types = [];
this.config.annotations.types.forEach((type) => types.push(type.contenttype));
return types;
return this.config.annotations.types.map((type) => type.contenttype);
},
},
created() {
this.icons = Icons;
},
mounted() {
this.$root.$on('update-content', async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
this.$root.$on('update-annotations', (content) => {
const parser = new DOMParser();
const doc = parser.parseFromString(content, 'text/html');
this.ids = [...doc.body.querySelectorAll('[id]')].map((el) => el.getAttribute('id'));
const ids = [...document.querySelectorAll('.ab')].map((x) => x.id);
const interval = setInterval(() => {
if (this.annotationLoading) {
this.types = this.filterAnnotationTypes();
this.ids = ids;
clearInterval(interval);
}
}, 500);
});
},
methods: {
......@@ -77,7 +102,7 @@ export default {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('aria-hidden', 'true');
svg.setAttribute('class', 'q-icon q-ml-sm');
svg.setAttribute('class', 'q-icon q-ml-xs');
svg.setAttribute('focusable', 'false');
svg.setAttribute('role', 'presentation');
svg.setAttribute('viewBox', viewBox);
......@@ -96,19 +121,17 @@ export default {
* @return array of annotations excluding unconfigured ones
*/
filterAnnotationTypes() {
const types = [];
this.annotations.forEach((annotation) => {
let id = annotation.target.id.split('/');
id = id[id.length - 1];
return this.annotations.filter((annotation) => {
const annotationIds = this.ids.includes(this.stripAnnotationId(annotation.target.id));
if (this.configuredTypes.filter((type) => type === annotation.body['x-content-type']).length > 0 && this.ids.some((x) => id.startsWith(x))) {
types.push(annotation);
// function is triggered on list rendering, so we use it as init call to set up the text
if (this.configuredTypes.find((type) => type === annotation.body['x-content-type']) && annotationIds) {
this.setText(annotation);
return true;
}
return false;
});
return types;
},
getIcon(contentType) {
......@@ -149,12 +172,25 @@ export default {
};
</script>
<style>
<style lang="scss">
/* not in scope to style the text */
.annotation {
border-bottom: 2px solid;
padding-bottom: 2px;
background-color: $grey-4;
border-bottom: 1px solid;
/**
* adding a linting exception here,
* because 1px is invalid, but needed here
* adding a global rule for this would introduce unnecessary error proneness
*/
/* stylelint-disable */
margin: 0 1px;
padding: 1px 1px 2px 1px;
/* stylelint-enable */
white-space: nowrap;
@media (prefers-color-scheme: dark) {
background-color: $grey-9;
}
}
.annotation-disabled {
......@@ -166,3 +202,17 @@ export default {
display: none;
}
</style>
<style lang="scss" scoped>
.q-item {
min-height: unset;
}
.q-item__section--avatar {
min-width: 24px;
}
.q-item__section--side {
padding-right: unset;
}
</style>
......@@ -112,15 +112,16 @@ export default {
fontsize() {
this.$refs.contentsize.style.fontSize = `${this.fontsize}px`;
},
activeTab(url) {
this.request(url, 'text').then((data) => {
if (this.supportType) {
this.getSupport(this.manifests[0].support);
}
this.content = data;
this.$root.$emit('update-content');
});
async activeTab(url) {
const data = await this.request(url, 'text');
if (this.supportType) {
this.getSupport(this.manifests[0].support);
}
this.content = data;
this.$root.$emit('update-annotations', data);
},
},
async created() {
......@@ -175,20 +176,20 @@ export default {
</script>
<style lang="scss" scoped>
.rtl {
direction: rtl;
}
.default-cursor {
cursor: default !important;
}
.item-content {
display: flex;
flex: 1;
flex-direction: column;
height: 100vh;
overflow: auto;
padding: 8px;
}
.rtl {
direction: rtl;
}
.default-cursor {
cursor: default !important;
}
.item-content {
display: flex;
flex: 1;
flex-direction: column;
height: 100vh;
overflow: auto;
padding: 8px;
}
</style>
<template>
<q-header :class="$q.dark.isActive ? 'bg-dark' : 'bg-secondary text-primary'">
<div class="header__wrap">
<q-toolbar>
<q-toolbar v-if="config.headers.info">
<Infobar
v-if="config.headers.info && manifests.length"
class="col-xs-9"
......@@ -10,6 +10,7 @@
:manifests="manifests"
/>
<div class="row no-wrap justify-end col-xs-3">
<!-- TODO: make component out of the following and re-use it to avoid duplication -->
<Language
v-if="standalone"
:config="config"
......@@ -34,6 +35,19 @@
v-if="config.headers.toggle"
:panels="panels"
/>
<div
v-if="!config.headers.info"
class="row no-wrap justify-end col-xs-3"
>
<!-- TODO: make component out of the following and re-use it to avoid duplication -->
<Language
v-if="standalone"
:config="config"
/>
<Color :projectcolors="projectcolors" />
<Softwareinfo />
</div>
</q-toolbar>
</div>
</div>
......
<template>
<q-card
bordered
flat
>
<q-card-section class="text-center">
<q-icon
:name="fasInfoCircle"
class="q-pr-sm"
color="red-9"
size="sm"
/>
<span class="text-body1 text-uppercase vertical-middle">{{ $t('notificationTitle') }}</span>
</q-card-section>
<q-separator inset />
<q-card-section class="text-body2 text-center">
{{ message }}
</q-card-section>
</q-card>
</template>
<script>
import { fasInfoCircle } from '@quasar/extras/fontawesome-v5';
export default {
name: 'Notification',
props: {
message: {
type: String,
default: () => '',
},
},
data() {
return {
};
},
created() {
this.fasInfoCircle = fasInfoCircle;
},
};
</script>
......@@ -35,6 +35,8 @@ export default {
Manuscript: 'Manuskript',
Metadata: 'Metadaten',
next: 'Näch.',
notificationTitle: 'Keine Annotationen verfügbar',
noAnnotationMessage: 'Die aktuelle Ansicht enthält keine Annotationen.',
Origin: 'Ursprung',
osdFullPage: 'Vollbildmodus wechseln',
osdHome: 'Ansicht zurücksetzen',
......
......@@ -35,6 +35,8 @@ export default {
Manuscript: 'Manuscript',
Metadata: 'Metadata',
next: 'Next',
notificationTitle: 'No Annotations available',
noAnnotationMessage: 'The current view has no annotations to display.',
Origin: 'Origin',
osdFullPage: 'Toggle full page',
osdHome: 'Go home',
......
......@@ -85,6 +85,10 @@ export default {
type: Array,
default: () => [],
},
annotationLoading: {
type: Boolean,
default: false,
},
collection: {
type: Object,
default: () => {},
......
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