Commit 6309d403 authored by schneider210's avatar schneider210
Browse files

update pkgs. extend panel config. rewrite toggle mechanism and event emitters....

update pkgs. extend panel config. rewrite toggle mechanism and event emitters. fix stylings for the panels
parent 58aa1248
......@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.0.23] - 2020-07-20
### Added
- hide image toggle and panel if no imageurl is provided
- panelnames are configurable. togglenames and captions are updated accordingly
### Fixed
- order of toggles corresponds to panels
## [0.0.22] - 2020-07-13
### Added
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "viewer",
"version": "0.0.1",
"version": "0.0.22",
"description": "Viewer for the modular framework to present digital editions",
"productName": "EMo Viewer",
"cordovaId": "de.uni-goettingen.sub.emo",
......@@ -10,7 +10,8 @@
"Frank Schneider <frank.schneider@sub.uni-goettingen.de>"
],
"contributors": [
"Nils Windisch"
"Nils Windisch",
"Manikanth Dindigala"
],
"private": true,
"scripts": {
......@@ -19,27 +20,26 @@
"lint": "eslint --ext .js,.vue src"
},
"dependencies": {
"@quasar/extras": "^1.7.0",
"@quasar/extras": "^1.8.2",
"openseadragon": "^2.4.2",
"quasar": "^1.12.4"
"quasar": "^1.12.11"
},
"devDependencies": {
"@quasar/app": "^1.9.6",
"autoprefixer": "^9.7.6",
"autoprefixer": "9.7.6",
"babel-eslint": "^10.0.1",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.21.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-vue": "^6.1.2",
"node-sass": "^4.14.1",
"sass": "^1.26.8",
"sass-loader": "^8.0.2"
"sass": "^1.26.10",
"sass-loader": "8.0.2"
},
"engines": {
"node": ">= 10.18.1",
"npm": ">= 6.13.4",
"yarn": ">= 1.21.1"
"npm": ">= 6.13.4"
},
"browserslist": [
"last 1 version, not dead, ie >= 11"
......
......@@ -4,10 +4,10 @@
<Header v-if="config.headers.all"
:collectiontitle="collectiontitle"
:config="config"
:imageurl="imageurl"
:itemlabel="itemlabel"
:itemurls="itemurls"
:manifests="manifests"
:status="status"
/>
<q-page-container>
......@@ -21,7 +21,6 @@
:language="itemlanguage"
:manifests="manifests"
:request="request"
:status="status"
:tree="tree"
/>
</q-page-container>
......@@ -49,13 +48,13 @@ export default {
config: {},
fontsize: 14,
imageurl: '',
isCollection: false,
itemlabel: '',
itemlanguage: '',
itemurl: '',
itemurls: [],
label: '',
manifests: [],
status: {},
tree: [],
};
},
......@@ -67,6 +66,8 @@ export default {
return data;
},
getCollection(url) {
this.isCollection = true;
this.request(url)
.then((data) => {
this.collection = data;
......@@ -91,10 +92,6 @@ export default {
},
getConfig() {
this.config = JSON.parse(document.getElementById('emo-config').text);
if (Object.keys(this.config.panels).length) {
this.status = this.config.panels;
}
},
getItemData(url) {
this.request(url)
......@@ -104,7 +101,8 @@ export default {
this.contenturl = data.content;
this.imageurl = data.image && data.image.id ? data.image.id : '';
this.itemlabel = data.n ? data.n : 'No itemlabel :(';
this.itemlanguage = data.language;
// eslint-disable-next-line prefer-destructuring
this.itemlanguage = data['x-langString'].split(',')[0];
});
},
getItemIndex(nodelabel) {
......@@ -148,6 +146,11 @@ export default {
getManifest(url) {
this.request(url)
.then((data) => {
// if the entrypoint points to a single manifest, initialize the tree
if (this.isCollection === false) {
this.tree.push({ label: '', 'label-key': this.config.labels.manifest, children: [] });
}
if (!Array.isArray(data.sequence)) {
data.sequence = [data.sequence];
}
......@@ -204,21 +207,18 @@ export default {
this.itemurls.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
},
mounted() {
this.$root.$on('update-fontsize', (fontsize) => {
this.fontsize = fontsize;
});
this.$root.$on('update-item', (url) => {
this.itemurl = url;
this.$router.push({ query: { itemurl: url } });
// NOTE: Set imageurl to an empty string. Otherwise, if there is no corresponding image,
// the "preceding" image according to the "preceding" itemurl will be shown.
// the "preceding" image according to the "preceding" item will be shown.
this.imageurl = '';
this.getItemData(url);
});
this.$root.$on('update-panel-status', (status) => {
this.status = status;
});
this.$root.$on('change-fontsize', (fontsize) => {
this.fontsize = fontsize;
});
},
};
</script>
......@@ -66,14 +66,14 @@ export default {
let textsize = this.fontsize;
textsize -= textsize > min ? 1 : 0;
this.$root.$emit('change-fontsize', textsize);
this.$root.$emit('update-fontsize', textsize);
},
increase() {
const max = 32;
let textsize = this.fontsize;
textsize += textsize < max ? 1 : 0;
this.$root.$emit('change-fontsize', textsize);
this.$root.$emit('update-fontsize', textsize);
},
getSupport(obj) {
if (obj.type === 'css') {
......
......@@ -15,23 +15,6 @@
{{ captionprev }}
</q-btn>
<!-- <q-input
color="teal"
class="q-mb-md"
dense
min="1"
standout
type="number"
:placeholder="config.labels.item"
>
<template v-slot:append>
<q-icon
:name="fasCheck"
size="20px"
/>
</template>
</q-input> -->
<q-btn
unelevated
class="q-mb-md"
......@@ -61,19 +44,6 @@ export default {
this.fasArrowLeft = fasArrowLeft;
this.fasCheck = fasCheck;
},
methods: {
toggleSheet(itemIndex) {
const link = this.itemurls[itemIndex];
const tree = document.getElementsByClassName('view-tree')[0];
window.location.hash = `selectedItem-${link}`;
tree.scrollBy(0, -80);
this.sequenceindex = this.computedsequenceindex;
this.updateItem(this.itemurls[itemIndex]);
this.updateSequenceIndex(this.sequenceindex);
},
},
};
</script>
......
......@@ -33,7 +33,8 @@
content-sm-center
justify-sm-evenly
row-sm"
:status="status"
:imageurl="imageurl"
:panelstates="config.panels"
/>
</div>
</q-header>
......@@ -54,10 +55,10 @@ export default {
props: {
collectiontitle: String,
config: Object,
imageurl: String,
itemlabel: String,
itemurls: Array,
manifests: Array,
status: Object,
},
};
</script>
......
<template>
<div class="q-pa-md q-gutter-sm">
<!-- <q-input
filled
label="Filter by label ..."
ref="filter"
v-model="filter"
>
<template v-slot:append>
<q-icon v-if="filter !== ''"
class="cursor-pointer"
@click="resetSearch"
:name="fasTimes"
/>
</template>
</q-input>
-->
<q-tree
class="view-tree"
label-key="label-key"
node-key="label"
:expanded.sync="expanded"
:filter="filter"
:filter-method="search"
:nodes="tree"
:selected.sync="selected"
>
......@@ -32,16 +15,11 @@
</div>
</template>
</q-tree>
<!-- ^^ these ones go up here
:filter="filter"
:filter-method="search"
-->
</div>
</template>
<script>
import matIcons from 'quasar/icon-set/material-icons';
// import { fasTimes } from '@quasar/extras/fontawesome-v5';
export default {
name: 'Treeview',
......@@ -52,24 +30,12 @@ export default {
data() {
return {
expanded: [],
// filter: '',
selected: this.manifests[0].sequence[0].id,
sequenceindex: 0,
};
},
// methods: {
// resetSearch() {
// this.filter = '';
// this.$refs.filter.focus();
// },
// search(node, filter) {
// const f = filter.toLowerCase();
// return node.label && node.label.toLowerCase().indexOf(f) > -1;
// },
// },
created() {
this.$q.iconSet.set(matIcons);
// this.fasTimes = fasTimes;
},
mounted() {
this.$root.$on('update-item', (item) => {
......
......@@ -5,14 +5,14 @@
dense
size="md"
class="q-mb-md"
v-for="(name, idx) in panels"
v-for="(name, idx) in togglekeys"
:aria-selected="toggleAria(idx)"
:key="idx"
:title="toggleTitle(idx)"
@click="updateStatus(idx)"
@click="toggleIcon(idx); updateStatus(idx)"
>
<q-icon class="q-pr-xs" size="xs" :name="toggleIcon(idx)" />
{{ name }}
{{ panelstates[name].name }}
</q-btn>
<q-btn
......@@ -40,11 +40,13 @@ import {
export default {
name: 'Togglebar',
props: {
status: Object,
imageurl: String,
panelstates: Object,
},
data() {
return {
panels: [],
togglekeys: [],
states: {},
};
},
filters: {
......@@ -53,28 +55,49 @@ export default {
},
},
methods: {
keyExists(needle = '', haystack = []) {
const index = haystack.indexOf(needle);
return [index > -1, index];
},
resetPanelStatus() {
for (let index = 0; index < this.panels.length; index += 1) {
this.status[this.panels[index]] = true;
// NOTE: just loop over the initial states formerly configured to be shown (e.g. *true*)
// filtered result goes into *togglekeys*.
// leave the initial panel/s configured to be not shown (e.g. *false*) untouched!
for (let idx = 0; idx < this.togglekeys.length; idx += 1) {
this.panelstates[this.togglekeys[idx]].show = true;
}
this.$root.$emit('update-panel-status', this.status);
this.$root.$emit('update-panel-status', this.updateEmitter(this.panelstates));
},
toggleAria(id) {
return !!this.status[this.panels[id]];
return !!this.panelstates[this.togglekeys[id]].show;
},
toggleIcon(id) {
return this.status[this.panels[id]] ? fasCheckCircle : fasCircle;
return this.panelstates[this.togglekeys[id]].show ? fasCheckCircle : fasCircle;
},
toggleTitle(id) {
const caption = this.ucfirst(this.panels[id]);
return this.status[this.panels[id]] ? `Hide ${caption} Tab` : `Show ${caption} Tab`;
const caption = this.ucfirst(this.panelstates[this.togglekeys[id]].name);
return this.panelstates[this.togglekeys[id]].show
? `Hide ${caption} Tab`
: `Show ${caption} Tab`;
},
ucfirst(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
},
updateEmitter(status) {
Object.entries(status).forEach(([panel, state]) => {
this.states[panel] = state.show;
});
return this.states;
},
updateStatus(id) {
this.status[this.panels[id]] = !this.status[this.panels[id]];
this.$root.$emit('update-panel-status', this.status);
// NOTE: leave the initial panelstates untouched! Configured by the project only!
// original panelstates needed in resetPanelStatus() to look up the initial states,
// which otherwise would be incidentally overwritten; hence: => *statecopy*
const statecopy = this.panelstates;
statecopy[this.togglekeys[id]].show = !statecopy[this.togglekeys[id]].show;
this.$root.$emit('update-panel-status', this.updateEmitter(statecopy));
},
},
created() {
......@@ -83,9 +106,24 @@ export default {
this.fasCheckCircle = fasCheckCircle;
// just show the toggle buttons needed according to the config
Object.entries(this.status).forEach(([panel, state]) => {
if (state === true) {
this.panels.push(panel);
Object.entries(this.panelstates).forEach(([panel, state]) => {
if (state.show === true) {
this.togglekeys.push(panel);
}
});
},
mounted() {
this.resetPanelStatus();
this.$root.$on('update-item', () => {
if (this.panelstates.image.show) {
const [haskey, index] = this.keyExists('image', this.togglekeys);
// check, if image key hasn't been deleted yet
if (haskey && !this.imageurl) {
this.togglekeys.splice(index, 1);
} else if (!haskey && this.imageurl) {
this.togglekeys.push('image');
}
}
});
},
......
......@@ -10,5 +10,11 @@
position: sticky;
top: 0;
width: 100%;
z-index: 999999;
}
}
.openseadragon-canvas {
&:focus {
outline: none;
}
}
......@@ -36,10 +36,26 @@
"manifest": "Manuscript"
},
"panels": {
"image": true,
"text": true,
"metadata": true,
"treeview": true
"tree": {
"name": "Contents",
"position": 1,
"show": true
},
"text": {
"name": "Text",
"position": 2,
"show": true
},
"image": {
"name": "Image",
"position": 3,
"show": true
},
"metadata": {
"name": "Metadata",
"position": 4,
"show": true
}
},
"standalone": true
}
......
......@@ -11,6 +11,17 @@ export default {
};
},
methods: {
toggleSheet(itemIndex) {
const link = this.itemurls[itemIndex];
const tree = document.getElementsByClassName('view-tree')[0];
window.location.hash = `selectedItem-${link}`;
tree.scrollBy(0, -80);
this.sequenceindex = this.computedsequenceindex;
this.updateItem(this.itemurls[itemIndex]);
this.updateSequenceIndex(this.sequenceindex);
},
updateItem() {
this.$root.$emit('update-item', this.itemurls[this.itemindex]);
},
......
......@@ -2,8 +2,8 @@
<q-page>
<q-splitter v-model="splitterone" :limits="[0, 100]">
<template v-show="panels.treeview" v-slot:before>
<Toolbar heading="Treeview" />
<template v-show="config.panels.tree.show && states.tree" v-slot:before>
<Toolbar :heading="config.panels.tree.name" />
<q-separator />
<Treeview v-if="tree.length && manifests.length"
......@@ -16,8 +16,8 @@
<template v-slot:after>
<q-splitter v-model="splittertwo" :limits="[0, 100]">
<template v-show="panels.text" v-slot:before>
<Toolbar heading="Text" />
<template v-show="config.panels.text.show && states.text" v-slot:before>
<Toolbar :heading="config.panels.text.name" />
<q-separator />
<div class="q-pa-md q-gutter-sm">
......@@ -40,8 +40,8 @@
<template v-slot:after>
<q-splitter v-model="splitterthree" :limits="[0, 100]">
<template v-show="panels.image && imageurl" v-slot:before>
<Toolbar heading="Image" />
<template v-show="config.panels.image.show && states.image && imageurl" v-slot:before>
<Toolbar :heading="config.panels.image.name" />
<q-separator />
<div class="q-pa-md q-gutter-sm" style="overflow:hidden">
......@@ -55,8 +55,8 @@
</div>
</template>
<template v-show="panels.metadata" v-slot:after>
<Toolbar heading="Metadata" />
<template v-show="config.panels.metadata.show && states.metadata" v-slot:after>
<Toolbar :heading="config.panels.metadata.name" />
<q-separator />
<div class="scrollPanel">
......@@ -106,34 +106,33 @@ export default {
language: String,
manifests: Array,
request: Function,
status: Object,
tree: Array,
},
data() {
return {
// status: image, text, metadata, treeview
// status: tree, text, image, metadata
matrix: [
{ state: [1, 1, 1, 1], ratio: [25, 33, 50] },
{ state: [0, 0, 0, 0], ratio: [0, 0, 0] },
{ state: [1, 1, 1, 0], ratio: [0, 33, 50] },
{ state: [1, 1, 0, 1], ratio: [33, 50, 100] },
{ state: [1, 1, 1, 0], ratio: [33, 50, 100] },
{ state: [1, 1, 0, 1], ratio: [33, 50, 0] },
{ state: [1, 0, 1, 1], ratio: [33, 0, 50] },
{ state: [1, 0, 1, 0], ratio: [0, 0, 50] },
{ state: [1, 0, 0, 1], ratio: [50, 0, 100] },
{ state: [1, 1, 0, 0], ratio: [0, 50, 100] },
{ state: [1, 0, 0, 0], ratio: [0, 0, 100] },
{ state: [0, 1, 1, 1], ratio: [33, 50, 0] },
{ state: [0, 1, 1, 0], ratio: [0, 50, 0] },
{ state: [0, 1, 0, 1], ratio: [50, 100, 0] },
{ state: [1, 0, 1, 0], ratio: [33, 0, 100] },
{ state: [1, 0, 0, 1], ratio: [50, 0, 0] },
{ state: [1, 1, 0, 0], ratio: [50, 100, 0] },
{ state: [1, 0, 0, 0], ratio: [100, 0, 0] },
{ state: [0, 1, 1, 1], ratio: [0, 33, 50] },
{ state: [0, 1, 1, 0], ratio: [0, 50, 100] },
{ state: [0, 1, 0, 1], ratio: [0, 50, 0] },
{ state: [0, 1, 0, 0], ratio: [0, 100, 0] },
{ state: [0, 0, 1, 1], ratio: [50, 0, 0] },
{ state: [0, 0, 1, 0], ratio: [0, 0, 0.1] },
{ state: [0, 0, 0, 1], ratio: [100, 0, 0] },
{ state: [0, 0, 1, 1], ratio: [0, 0, 50] },
{ state: [0, 0, 1, 0], ratio: [0, 0, 100] },
{ state: [0, 0, 0, 1], ratio: [0, 0, 0] },
],
panels: {},
splitterone: 25,
splittertwo: 33,
splitterthree: 50,
states: {},
};
},
methods: {
......@@ -146,27 +145,37 @@ export default {
return activePanels;
},
// hide image panel if the actual item doesn't contain an imageurl
setPanelState() {
this.states.image = this.config.panels.image.show && !(this.imageurl === '');