From cdb850b9ebdcc88e0f59036c7dfb6f6e1dd6e2a2 Mon Sep 17 00:00:00 2001 From: Johannes Kepper Date: Thu, 8 Feb 2024 14:17:22 +0100 Subject: [PATCH] xml editor and other fun (wip) --- src/components/DiploTab.vue | 9 +- src/components/DiploTabMenu.vue | 116 +++++++++++++++ src/components/FacsimileComponent.vue | 56 +++++++- src/components/SliderInput.vue | 39 +++-- src/components/XmlEditor.vue | 4 + src/components/shared/VerovioComponent.vue | 5 + src/css/_variables.scss | 2 + src/store/data/index.js | 159 ++++++++++++++++++++- src/store/gui/index.js | 2 +- src/store/vrv/index.js | 3 +- 10 files changed, 376 insertions(+), 19 deletions(-) create mode 100644 src/components/DiploTabMenu.vue diff --git a/src/components/DiploTab.vue b/src/components/DiploTab.vue index c37fc67..08e238f 100644 --- a/src/components/DiploTab.vue +++ b/src/components/DiploTab.vue @@ -33,6 +33,7 @@
+
@@ -57,6 +58,8 @@ import FacsimileComponent from '@/components/FacsimileComponent.vue' import VerovioComponent from '@/components/shared/VerovioComponent.vue' import XmlEditor from '@/components/XmlEditor.vue' +import DiploTabMenu from '@/components/DiploTabMenu.vue' + export default { name: 'DiploTab', components: { @@ -68,7 +71,8 @@ export default { WritingZoneDirectory, FacsimileComponent, VerovioComponent, - XmlEditor + XmlEditor, + DiploTabMenu }, methods: { toggleSidebar () { @@ -139,11 +143,12 @@ export default { return false } - // console.log('DiploTab: autoTranscribe()') + console.log('DiploTab: autoTranscribe()', newShapes, oldShapes, newAnnotated, oldAnnotated) if (newAnnotated === oldAnnotated && newShapes.length > oldShapes.length && oldShapes.length > 0) { // add shape to existing diploTrans console.log('TODO: add shape to existing diploTrans') + this.$store.dispatch('diploTranscribe_setShapes', { annotElem: newAnnotated, shapes: newShapes }) } else { this.$store.dispatch('diploTranscribe') } diff --git a/src/components/DiploTabMenu.vue b/src/components/DiploTabMenu.vue new file mode 100644 index 0000000..df692d6 --- /dev/null +++ b/src/components/DiploTabMenu.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/src/components/FacsimileComponent.vue b/src/components/FacsimileComponent.vue index 802c089..11af451 100644 --- a/src/components/FacsimileComponent.vue +++ b/src/components/FacsimileComponent.vue @@ -167,7 +167,7 @@ export default { click.page = clickedPagePos // } - console.log('-------------\n\nCLICK\n\n------------\n', click) + // console.log('-------------\n\nCLICK\n\n------------\n', click) // check for click to svg shape if (click.target.localName === 'path') { @@ -506,6 +506,7 @@ export default { if (activeZone) { svgClone.querySelector('#' + activeZone.svgGroupWzId).classList.add('activeWritingZone') + this.indicateUsedShapes() } if (activeZone && activeWritingLayer) { @@ -517,6 +518,41 @@ export default { } }, + /** + * indicates which shapes are already used in the active diploTrans + * @return {[type]} [description] + */ + indicateUsedShapes () { + const arr = [...this.$store.getters.activeDiploTransUsedShapes] + console.log('FacsimileComponent:indicateUsedShapes(): starting with this array:\n', arr) + const existingOverlay = this.$refs.container.querySelector('.svgContainer.shapes') + + if (existingOverlay !== null) { + console.log('found an overlay') + existingOverlay.querySelectorAll('.activeWritingZone .usedShape').forEach(shape => { + const id = shape.getAttribute('data-id') + const index = arr.indexOf(id) + if (index === -1) { + console.log('removing usedShape from ' + id) + shape.classList.remove('usedShape') + } else { + arr.splice(index, 1) + } + }) + + console.log('\n\nNEED TO ADD in following array\n', arr) + arr.forEach(id => { + const elem = existingOverlay.querySelector('.activeWritingZone path[id="' + id + '"]') + if (elem) { + console.log('adding usedShape to ' + id) + elem.classList.add('usedShape') + } else { + console.log('unable to find element with id ' + id + '\n', this.$refs.container.querySelectorAll('path')) + } + }) + } + }, + /** * renders system overlays * @return {[type]} [description] @@ -1064,6 +1100,11 @@ export default { this.renderDiploTransOnPage() }) + this.unwatchUsedShapes = this.$store.watch((state, getters) => getters.activeDiploTransUsedShapes, + (newArr, oldArr) => { + this.indicateUsedShapes() + }) + this.openFacsimile() }, updated () { @@ -1085,6 +1126,7 @@ export default { this.unwatchDiploTransOsdBounds() this.unwatchDiploTranscriptsOnCurrentPage() } + this.unwatchUsedShapes() } catch (err) { console.warn('FacsimileComponent:beforeUnmount(): ' + err, err) } @@ -1250,6 +1292,16 @@ export default { opacity: 1; fill: $svgActiveWritingLayerColor; stroke: $svgActiveWritingLayerColor; + + &.usedShape { + fill: $svgUsedShapeColor; + stroke: $svgUsedShapeColor; + } + } + + .usedShape { + fill: $svgUsedShapeColor; + stroke: $svgUsedShapeColor; } } } @@ -1357,7 +1409,7 @@ export default { .overlay.diploTrans { &.activeDiploTrans { - outline: 5px solid $svgActiveWritingLayerColor; + // outline: 5px solid $svgActiveWritingLayerColor; } g.staff > path { fill: $svgActiveWritingZoneColor; //transparent; diff --git a/src/components/SliderInput.vue b/src/components/SliderInput.vue index 064bec9..b5875ae 100644 --- a/src/components/SliderInput.vue +++ b/src/components/SliderInput.vue @@ -8,7 +8,7 @@ :min="min" :max="max" :step="step" - :disabled="readOnly" + :disabled="disabled" :style="{ background: 'linear-gradient(to right, #999 ' + percent + '%, #ccc ' + percent + '%)'}"/>
@@ -62,20 +62,43 @@ export default { }, computed: { percent () { - const val = parseFloat(this.$store.getters[this.getterName]) + let val + + try { + if (this.idParam === 'undefined') { + val = parseFloat(this.$store.getters[this.getterName]) + } else { + val = parseFloat(this.$store.getters[this.getterName](this.idParam)) + } + } catch (e) { + val = parseFloat(this.$store.getters[this.getterName]) + } const dist = this.max - this.min const pos = val - this.min const percent = parseInt(100 / dist * pos) return percent }, + disabled () { + if (this.readOnly) { + return this.readOnly + } + return this.data === null || isNaN(this.data) + }, data: { get () { - if (typeof this.getterName !== 'undefined') { + try { + // console.warn('----\nSliderInput\ngetterName: ', this.getterName, '\nidParam: ', this.idParam, '\nval: ', this.$store.getters[this.getterName](this.idParam)) + if (this.getterName !== 'undefined' && this.idParam !== 'undefined') { + return parseFloat(this.$store.getters[this.getterName](this.idParam)) + } else if (typeof this.getterName !== 'undefined') { + return parseFloat(this.$store.getters[this.getterName]) + } else if (typeof this.val !== 'undefined') { + return parseFloat(this.val) + } else { + return parseFloat(this.$store.getters[this.getterName](this.idParam)) + } + } catch (e) { return parseFloat(this.$store.getters[this.getterName]) - } else if (typeof this.val !== 'undefined') { - return parseFloat(this.val) - } else { - return parseFloat(this.$store.getters[this.getterName](this.idParam)) } }, set (value) { @@ -100,7 +123,7 @@ export default { } .simplifiedSlider { - width: 3em; + width: 3.6em; text-align: center; border: $lightBorder; border-radius: 3px; diff --git a/src/components/XmlEditor.vue b/src/components/XmlEditor.vue index 1cb800a..9b103fb 100644 --- a/src/components/XmlEditor.vue +++ b/src/components/XmlEditor.vue @@ -6,6 +6,7 @@ :autofocus="true" :indent-with-tab="true" :tab-size="2" + :disabled="disabled" :extensions="extensions" /> @@ -47,6 +48,9 @@ export default { // console.log('changing editor to ', val) this.$store.dispatch('modifyXml', { filePath: this.filePath, id: this.id, val }) } + }, + disabled () { + return this.code === '' } } } diff --git a/src/components/shared/VerovioComponent.vue b/src/components/shared/VerovioComponent.vue index aa26fc0..5d37708 100644 --- a/src/components/shared/VerovioComponent.vue +++ b/src/components/shared/VerovioComponent.vue @@ -189,6 +189,11 @@ export default { max-height: 100%; overflow: auto; + svg *[data-corresp] { + fill: $svgUsedShapeColor; + stroke: $svgUsedShapeColor; + } + svg .supplied { fill: $svgSuppliedColor; stroke: $svgSuppliedColor; diff --git a/src/css/_variables.scss b/src/css/_variables.scss index cabe158..809b8ea 100644 --- a/src/css/_variables.scss +++ b/src/css/_variables.scss @@ -30,4 +30,6 @@ $svgUnassignedShapeColor: #ff00ff; $svgActiveWritingZoneColor: $highlightColor06; //#468ffc; $svgActiveWritingLayerColor: $highlightColor05; +$svgUsedShapeColor: rgb(0, 161, 46); + $scoreHighlightedColor: $highlightColor01; diff --git a/src/store/data/index.js b/src/store/data/index.js index 1fc4089..bbbc273 100644 --- a/src/store/data/index.js +++ b/src/store/data/index.js @@ -1407,6 +1407,7 @@ const dataModule = { let annotStaffN if (annotElemRef.name === 'barLine') { + // todo: find better value for staff of the barline annotStaffN = 1 } else { annotStaffN = annotElem.closest('staff').getAttribute('n') @@ -1476,6 +1477,25 @@ const dataModule = { dispatch('loadDocumentIntoStore', { path: atPath, dom: atDoc }) dispatch('logChange', { path: atPath, baseMessage, param, xmlIDs: [annotElemRef.id], isNewDocument: false }) + + dispatch('setActiveDiploTransElementId', diplomaticElement.getAttribute('xml:id')) + }, + + /** + * sets shapes of the current active element + * @param {*} param0 + * @param {*} shapes + */ + diploTranscribe_setShapes ({ commit, getters, dispatch }, { annotElem, shapes }) { + console.log('diploTranscribe_setShapes', annotElem, shapes) + + const atDoc = getters.annotatedTranscriptForCurrentWz + // const dtDoc = getters.diplomaticTranscriptForCurrentWz.cloneNode(true) + + const atElem = atDoc.querySelector(annotElem.name + '[*|id="' + annotElem.id + '"]') + const corresp = atElem.getAttribute('corresp') + + console.log('searching for corresponding element in diplomatic transcript: ' + corresp) }, modifyXml ({ commit, getters, state, dispatch }, { filePath, id, val }) { @@ -1507,6 +1527,41 @@ const dataModule = { dispatch('loadDocumentIntoStore', { path: filePath, dom: file }) dispatch('logChange', { path: filePath, baseMessage, param, xmlIDs: [id], isNewDocument: false }) + }, + + /** + * sets an attribute value of the currently active element in the + * XML editor of the DiploTab + * @param {*} param0 + * @param {*} param1 + * @returns + */ + setActiveDiploTransElementAttValue ({ getters, dispatch }, { id, value }) { + const filePath = getters.currentWritingZoneObject?.diploTrans + const elemId = getters.activeDiploTransElementId + const attName = id + + if (!filePath || !elemId) { + return + } + const doc = getters.documentByPath(filePath) + if (!doc) { + return + } + + const newDoc = doc.cloneNode(true) + const elem = newDoc.querySelector('*[*|id="' + elemId + '"]') + + if (!elem) { + return + } + + elem.setAttribute(attName, value) + const baseMessage = 'adjust XML for ' + const param = '//' + elem.localName + '#' + elemId + + dispatch('loadDocumentIntoStore', { path: filePath, dom: newDoc }) + dispatch('logChange', { path: filePath, baseMessage, param, xmlIDs: [elemId], isNewDocument: false }) } }, @@ -2835,27 +2890,121 @@ const dataModule = { */ xmlSnippet: (state, getters) => ({ filePath, id }) => { if (!filePath || !id) { - return '' + return 'error 1' } - const doc = getters.documentByPath(filePath) + // const doc = getters.diplomaticTranscriptForCurrentWz.cloneNode(true) + const doc = getters.documentByPath(filePath).cloneNode(true) if (!doc) { - return '' + return 'error 2' } if (!state.isWellformed) { return state.temporaryXMLCode } - const elem = doc.querySelector('*[*|id="' + id + '"]') + console.log('------\nid: ' + id) + console.log(doc.querySelector('layer')) + + const allElems = doc.querySelectorAll('layer *[*|id]') + console.log([...allElems]) + const elem = [...allElems].find(elem => elem.getAttribute('xml:id') === id) + + // const elem = doc.querySelector('*[*|id="' + id + '"]') if (!elem) { - return '' + console.log('found doc:\n', doc.querySelector('layer')) + return 'error 3' } // console.log('found elem:\n', elem) return serializer.serializeToString(elem) + }, + + /** + * retrieves the name of the element currently activated in the XML editor of DiploTab + * @param {*} state + * @param {*} getters + * @returns + */ + activeDiploTransElementName: (state, getters) => { + const filePath = getters.currentWritingZoneObject?.diploTrans + const elemId = getters.activeDiploTransElementId + if (!filePath || !elemId) { + return null + } + + const doc = getters.documentByPath(filePath) + if (!doc) { + return null + } + const elem = doc.querySelector('*[*|id="' + elemId + '"]') + + if (!elem) { + return null + } + + return elem.localName + }, + + /** + * retrieves the attribute value of the element currently + * activated in the XML editor of DiploTab + * @param {*} state + * @param {*} getters + * @returns + */ + activeDiploTransElementAttValue: (state, getters) => (attName) => { + // const attName = 'coord.x1' + const filePath = getters.currentWritingZoneObject?.diploTrans + const elemId = getters.activeDiploTransElementId + if (!filePath || !elemId) { + return null + } + + const doc = getters.documentByPath(filePath) + if (!doc) { + return null + } + const elem = doc.querySelector('*[*|id="' + elemId + '"]') + + if (!elem) { + return null + } + + if (!elem.hasAttribute(attName)) { + return null + } + + return elem.getAttribute(attName) + }, + + /** + * returns a list of all SVG paths referenced by the current diplomatic transcript + * @param {*} state + * @param {*} getters + * @returns + */ + activeDiploTransUsedShapes: (state, getters) => { + const filePath = getters.currentWritingZoneObject?.diploTrans + if (!filePath) { + return [] + } + + const doc = getters.documentByPath(filePath) + if (!doc) { + return [] + } + + const arr = [] + doc.querySelectorAll('*[facs]').forEach(elem => { + const shapes = elem.getAttribute('facs').trim().replace(/\s+/g, ' ').split(' ') + shapes.forEach(uri => { + arr.push(uri.split('#')[1]) + }) + }) + return arr } } } diff --git a/src/store/gui/index.js b/src/store/gui/index.js index bd2366c..d7e298d 100644 --- a/src/store/gui/index.js +++ b/src/store/gui/index.js @@ -53,7 +53,7 @@ const guiModule = { pageTabSidebarVisible: true, pageTabSidebarWidth: 310, pageTabRightSidebarVisible: true, - pageTabRightSidebarWidth: 450, + pageTabRightSidebarWidth: 480, pageShowGrid: true, zonesTabLeftSidebarVisible: true, zonesTabLeftSidebarWidth: 310, diff --git a/src/store/vrv/index.js b/src/store/vrv/index.js index 4b5042d..5336058 100644 --- a/src/store/vrv/index.js +++ b/src/store/vrv/index.js @@ -87,7 +87,8 @@ const verovioModule = { svgRemoveXlink: true, svgHtml5: true, header: 'none', - footer: 'none' //, + footer: 'none', + svgAdditionalAttribute: ['beam@corresp', 'note@corresp', 'chord@corresp', 'measure@corresp', 'rest@corresp', 'slur@corresp'] //, // unit: 18 }