From 199c08f7ac8316d52f977486cf40fa8318fe45dc Mon Sep 17 00:00:00 2001 From: Jamie Cope Date: Wed, 5 Jun 2024 12:41:05 -0400 Subject: [PATCH 01/20] Reorder Story view includes to support Explorer as well in the same DOM --- source/client/ui/story/MainView.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/client/ui/story/MainView.ts b/source/client/ui/story/MainView.ts index 63039fe0..3a3aa09b 100644 --- a/source/client/ui/story/MainView.ts +++ b/source/client/ui/story/MainView.ts @@ -15,6 +15,8 @@ * limitations under the License. */ +import ExplorerPanel from "./ExplorerPanel"; + import parseUrlParameter from "@ff/browser/parseUrlParameter"; import localStorage from "@ff/browser/localStorage"; @@ -30,7 +32,7 @@ import NavigatorPanel from "./NavigatorPanel"; import CVTaskProvider, { ETaskMode } from "../../components/CVTaskProvider"; import TaskBar from "./TaskBar"; -import ExplorerPanel from "./ExplorerPanel"; + import EditorPanel from "./EditorPanel"; import TourPanel from "./TourPanel"; import TaskPanel from "./TaskPanel"; From d327739eabe33013a1a6d7f4e10ec60cb72c4c83 Mon Sep 17 00:00:00 2001 From: Jamie Cope Date: Wed, 5 Jun 2024 13:29:58 -0400 Subject: [PATCH 02/20] Fix for #276. Handle when rounded number inputs match existing values and don't trigger UI update --- source/client/ui/PropertyNumber.ts | 41 ++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/source/client/ui/PropertyNumber.ts b/source/client/ui/PropertyNumber.ts index 5c38d5db..69793d36 100644 --- a/source/client/ui/PropertyNumber.ts +++ b/source/client/ui/PropertyNumber.ts @@ -89,19 +89,7 @@ export default class PropertyNumber extends CustomElement const value = this.value; let text :string; - if(!isFinite(value)){ - text = value > 0 ? "inf" : "-inf"; - }else{ - const precision = schema.precision !== undefined - ? schema.precision : PropertyField.defaultPrecision; - - if (schema.percent) { - text = (value * 100).toFixed(precision - 2); - } else { - text = value.toFixed(precision); - } - - } + text = this.setPrecision(value); return html` @@ -132,6 +120,26 @@ export default class PropertyNumber extends CustomElement } } + protected setPrecision(value: number) : string { + const schema = this.property.schema; + let text :string; + + if(!isFinite(value)){ + text = value > 0 ? "inf" : "-inf"; + } + else{ + const precision = schema.precision !== undefined + ? schema.precision : PropertyField.defaultPrecision; + + if (schema.percent) { + text = (value * 100).toFixed(precision - 2); + } else { + text = value.toFixed(precision); + } + } + return text; + } + protected onChange = (event: Event) => { let text = (event.target as HTMLInputElement).value; @@ -145,6 +153,13 @@ export default class PropertyNumber extends CustomElement text = text.slice(0, -1); } value = +text / 100; + + // Handle special case where precision-rounded number will match current widget text. + // Lit sees it as unchanged and will not re-render the widget. + const currentValueText = this.setPrecision(this.value); + if(this.setPrecision(value) == currentValueText) { + (event.target as HTMLInputElement).value = currentValueText; + } }else{ value = parseFloat(text); } From 8cb35a21a2fc9a1f2c50fad1c7b6a89f18229dd2 Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Thu, 6 Jun 2024 15:47:09 +0200 Subject: [PATCH 03/20] use DEFAULT_LANGUAGE everywhere --- source/client/components/CVAnnotationsTask.ts | 4 ++-- source/client/components/CVArticlesTask.ts | 2 +- source/client/components/CVAudioTask.ts | 4 ++-- source/client/components/CVLanguageManager.ts | 7 ++++--- source/client/components/CVTaskProvider.ts | 4 ++-- source/client/components/CVToursTask.ts | 2 +- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/source/client/components/CVAnnotationsTask.ts b/source/client/components/CVAnnotationsTask.ts index 438e3720..9a790173 100644 --- a/source/client/components/CVAnnotationsTask.ts +++ b/source/client/components/CVAnnotationsTask.ts @@ -57,13 +57,13 @@ export default class CVAnnotationsTask extends CVTask protected static readonly ins = { mode: types.Enum("Mode", EAnnotationsTaskMode, EAnnotationsTaskMode.Off), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType.EN]), + language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), audio: types.Option("Annotation.Audio", ["None"], 0), selection: types.Event("Annotation.Selection") }; protected static readonly outs = { - language: types.Enum("Interface.Language", ELanguageType, ELanguageType.EN), + language: types.Enum("Interface.Language", ELanguageType, ELanguageType[DEFAULT_LANGUAGE]), }; ins = this.addInputs(CVAnnotationsTask.ins); diff --git a/source/client/components/CVArticlesTask.ts b/source/client/components/CVArticlesTask.ts index 7371f64e..81801da8 100644 --- a/source/client/components/CVArticlesTask.ts +++ b/source/client/components/CVArticlesTask.ts @@ -58,7 +58,7 @@ export default class CVArticlesTask extends CVTask lead: types.String("Article.Lead"), tags: types.String("Article.Tags"), uri: types.String("Article.URI"), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType.EN]), + language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), }; protected static readonly outs = { diff --git a/source/client/components/CVAudioTask.ts b/source/client/components/CVAudioTask.ts index b765c6e2..057937b0 100644 --- a/source/client/components/CVAudioTask.ts +++ b/source/client/components/CVAudioTask.ts @@ -23,7 +23,7 @@ import AudioTaskView from "../ui/story/AudioTaskView"; import { Node } from "@ff/graph/Component"; import CVDocument from "./CVDocument"; import CVAudioManager from "./CVAudioManager"; -import { ELanguageStringType, ELanguageType } from "client/schema/common"; +import { DEFAULT_LANGUAGE, ELanguageStringType, ELanguageType } from "client/schema/common"; //////////////////////////////////////////////////////////////////////////////// @@ -44,7 +44,7 @@ export default class CVAudioTask extends CVTask filepath: types.String("Audio.Filepath", null), captionPath: types.String("Audio.CaptionPath", null), isNarration: types.Boolean("Audio.IsNarration", false), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType.EN]), + language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), }; protected static readonly outs = { diff --git a/source/client/components/CVLanguageManager.ts b/source/client/components/CVLanguageManager.ts index 88c1251e..2d6b17b5 100644 --- a/source/client/components/CVLanguageManager.ts +++ b/source/client/components/CVLanguageManager.ts @@ -46,11 +46,12 @@ export default class CVLanguageManager extends Component protected static readonly ins = { enabled: types.Boolean("Language.Enabled", false), - language: types.Enum("Interface.Language", ELanguageType, ELanguageType.EN), + language: types.Enum("Interface.Language", ELanguageType, ELanguageType[DEFAULT_LANGUAGE]), }; protected static readonly outs = { - language: types.Enum("Interface.Language", ELanguageType, ELanguageType.EN), + /* exception to default language: in absence of any dictionary, this is always EN */ + language: types.Enum("Interface.Language", ELanguageType, ELanguageType.EN ), }; ins = this.addInputs(CVLanguageManager.ins); @@ -114,7 +115,7 @@ export default class CVLanguageManager extends Component const language = ELanguageType[data.language || "EN"]; if(language != outs.language.value && ins.language.value === outs.language.value) { - ins.language.setValue(isFinite(language) ? language : ELanguageType.EN); + ins.language.setValue(isFinite(language) ? language : ELanguageType[DEFAULT_LANGUAGE]); } } diff --git a/source/client/components/CVTaskProvider.ts b/source/client/components/CVTaskProvider.ts index 18bb1b33..efdf3f03 100644 --- a/source/client/components/CVTaskProvider.ts +++ b/source/client/components/CVTaskProvider.ts @@ -25,7 +25,7 @@ import CComponentProvider, { import CVTask from "./CVTask"; import taskSets, { ETaskMode } from "../applications/taskSets"; -import { ELanguageStringType, ELanguageType } from "client/schema/common"; +import { DEFAULT_LANGUAGE, ELanguageStringType, ELanguageType } from "client/schema/common"; import CVLanguageManager from "./CVLanguageManager"; //////////////////////////////////////////////////////////////////////////////// @@ -47,7 +47,7 @@ export default class CVTaskProvider extends CComponentProvider protected static readonly ins = { mode: types.Enum("Tasks.Mode", ETaskMode), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType.EN]), + language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), }; ins = this.addInputs(CVTaskProvider.ins); diff --git a/source/client/components/CVToursTask.ts b/source/client/components/CVToursTask.ts index 1c04d4ce..6806a12c 100644 --- a/source/client/components/CVToursTask.ts +++ b/source/client/components/CVToursTask.ts @@ -54,7 +54,7 @@ export default class CVToursTask extends CVTask stepCurve: types.Enum("Step.Curve", EEasingCurve), stepDuration: types.Number("Step.Duration", 1), stepThreshold: types.Percent("Step.Threshold", 0.5), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType.EN]), + language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), }; protected static readonly outs = { From b7bac8f8bbf9e52cab6bc388ff05a5f639652e8c Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 09:26:21 +0200 Subject: [PATCH 04/20] show full-text for CVLanguageManager.ins.language in property views --- source/client/components/CVLanguageManager.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/client/components/CVLanguageManager.ts b/source/client/components/CVLanguageManager.ts index 2d6b17b5..e7a6fee1 100644 --- a/source/client/components/CVLanguageManager.ts +++ b/source/client/components/CVLanguageManager.ts @@ -20,6 +20,7 @@ import { ILanguage, ILanguageOption } from "client/schema/setup"; import { ELanguageType, TLanguageType, ELanguageStringType, DEFAULT_LANGUAGE } from "client/schema/common"; import CVAssetReader from "./CVAssetReader"; import { ITagUpdateEvent } from "./CVModel2"; +import { enumToArray } from "@ff/core/types"; //////////////////////////////////////////////////////////////////////////////// @@ -46,7 +47,11 @@ export default class CVLanguageManager extends Component protected static readonly ins = { enabled: types.Boolean("Language.Enabled", false), - language: types.Enum("Interface.Language", ELanguageType, ELanguageType[DEFAULT_LANGUAGE]), + language: types.Enum("Interface.Language", ELanguageType, { + preset: ELanguageType[DEFAULT_LANGUAGE], + enum: ELanguageType, + options: enumToArray(ELanguageStringType).map(key => ELanguageStringType[key]) + }), }; protected static readonly outs = { From 49cf2a4b4ec0903430a7fef353e14d3f55381754 Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 09:27:02 +0200 Subject: [PATCH 05/20] remove TaskProvider's local language setting --- source/client/components/CVTaskProvider.ts | 10 ---------- source/client/ui/story/CollectionPanel.ts | 7 +------ 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/source/client/components/CVTaskProvider.ts b/source/client/components/CVTaskProvider.ts index efdf3f03..1acd4194 100644 --- a/source/client/components/CVTaskProvider.ts +++ b/source/client/components/CVTaskProvider.ts @@ -47,7 +47,6 @@ export default class CVTaskProvider extends CComponentProvider protected static readonly ins = { mode: types.Enum("Tasks.Mode", ETaskMode), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), }; ins = this.addInputs(CVTaskProvider.ins); @@ -78,15 +77,6 @@ export default class CVTaskProvider extends CComponentProvider taskSet.forEach(taskType => this.createComponent(taskType)); } - if(ins.language.changed) { - const newLanguage = ELanguageType[ELanguageType[ins.language.value]]; - - if(languageManager) { - languageManager.addLanguage(newLanguage); // add in case this is a currently inactive language - languageManager.ins.language.setValue(newLanguage); - } - } - return true; } diff --git a/source/client/ui/story/CollectionPanel.ts b/source/client/ui/story/CollectionPanel.ts index 6741e736..1d798dd7 100644 --- a/source/client/ui/story/CollectionPanel.ts +++ b/source/client/ui/story/CollectionPanel.ts @@ -38,18 +38,13 @@ export default class CollectionPanel extends DocumentView protected render() { - const taskProvider = this.taskProvider; const languageManager = this.activeDocument.setup.language; - if(taskProvider.ins.language.value !== languageManager.outs.language.value) - { - taskProvider.ins.language.setValue(languageManager.outs.language.value, true); - } return html`
Collection
- +
Title
From 8acf76bda6722aabbecd9c1bd4a868aacc9dd17c Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 09:17:15 +0200 Subject: [PATCH 06/20] remove TourTask's local language setting --- source/client/components/CVToursTask.ts | 22 ---------------------- source/client/ui/story/TourPanel.ts | 3 ++- source/client/ui/story/ToursTaskView.ts | 7 ++++--- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/source/client/components/CVToursTask.ts b/source/client/components/CVToursTask.ts index 6806a12c..eefb9582 100644 --- a/source/client/components/CVToursTask.ts +++ b/source/client/components/CVToursTask.ts @@ -54,7 +54,6 @@ export default class CVToursTask extends CVTask stepCurve: types.Enum("Step.Curve", EEasingCurve), stepDuration: types.Number("Step.Duration", 1), stepThreshold: types.Percent("Step.Threshold", 0.5), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), }; protected static readonly outs = { @@ -102,13 +101,6 @@ export default class CVToursTask extends CVTask const languageManager = this.activeDocument.setup.language; - if(ins.language.changed) { - const newLanguage = ELanguageType[ELanguageType[ins.language.value]]; - - languageManager.addLanguage(newLanguage); // add in case this is a currently inactive language - languageManager.ins.language.setValue(newLanguage); - //outs.language.setValue(newLanguage); - } if (tour) { const stepList = tour.steps; @@ -232,8 +224,6 @@ export default class CVToursTask extends CVTask if (this.tours) { this.tours.ins.enabled.setValue(true); } - - this.synchLanguage(); } deactivateTask() @@ -305,18 +295,6 @@ export default class CVToursTask extends CVTask this.onTourChange(); this.onStepChange(); tours.ins.tourIndex.setValue(tours.outs.tourIndex.value); // trigger UI refresh - - this.synchLanguage(); } - // Make sure this task language matches document - protected synchLanguage() { - const {ins} = this; - const languageManager = this.activeDocument.setup.language; - - if(ins.language.value !== languageManager.outs.language.value) - { - ins.language.setValue(languageManager.outs.language.value, true); - } - } } \ No newline at end of file diff --git a/source/client/ui/story/TourPanel.ts b/source/client/ui/story/TourPanel.ts index 2632f654..8371b47e 100644 --- a/source/client/ui/story/TourPanel.ts +++ b/source/client/ui/story/TourPanel.ts @@ -95,6 +95,7 @@ export default class TourPanel extends DocumentView const task = this.toursTask; const tours = this.tours; const machine = tours.snapshots; + const languageManager = this.activeDocument.setup.language; if (!task || !tours.ins.enabled.value) { return html`
Tour edit task not available.
`; @@ -122,7 +123,7 @@ export default class TourPanel extends DocumentView this.stateTable.rows = tours.activeSteps.map(step => { const state = machine.getState(step.id); return { - title: step.titles[ELanguageType[this.toursTask.ins.language.value]] || "undefined", + title: step.titles[ELanguageType[languageManager.ins.language.value]] || "undefined", curve: EEasingCurve[state.curve], duration: state.duration.toFixed(1) + "s", threshold: (state.threshold * 100).toFixed(0) + "%", diff --git a/source/client/ui/story/ToursTaskView.ts b/source/client/ui/story/ToursTaskView.ts index 07e76faa..671a9d4a 100644 --- a/source/client/ui/story/ToursTaskView.ts +++ b/source/client/ui/story/ToursTaskView.ts @@ -78,9 +78,10 @@ export default class ToursTaskView extends TaskView const tourList = tours.tours; const activeTour = tours.activeTour; const props = task.ins; + const languageManager = this.activeDocument.setup.language; const detailView = activeTour ? html`
- +
Title
Tags
@@ -98,10 +99,10 @@ export default class ToursTaskView extends TaskView
-
${ELanguageStringType[DEFAULT_LANGUAGE]}
${ELanguageStringType[ELanguageType[this.task.ins.language.value] as TLanguageType]}
+
${ELanguageStringType[DEFAULT_LANGUAGE]}
${ELanguageStringType[ELanguageType[languageManager.ins.language.value] as TLanguageType]}
- +
From 69b59c895e63aa0a608cd374880b78c45d1e5f2b Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 09:23:11 +0200 Subject: [PATCH 07/20] remove AudioTask's local language setting --- source/client/components/CVAudioTask.ts | 33 ++++++------------------- source/client/ui/story/AudioTaskView.ts | 3 ++- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/source/client/components/CVAudioTask.ts b/source/client/components/CVAudioTask.ts index 057937b0..473e3e95 100644 --- a/source/client/components/CVAudioTask.ts +++ b/source/client/components/CVAudioTask.ts @@ -44,7 +44,6 @@ export default class CVAudioTask extends CVTask filepath: types.String("Audio.Filepath", null), captionPath: types.String("Audio.CaptionPath", null), isNarration: types.Boolean("Audio.IsNarration", false), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), }; protected static readonly outs = { @@ -83,8 +82,6 @@ export default class CVAudioTask extends CVTask //this.nodeProvider.activeNode = this.nodeProvider.scopedNodes[0]; super.activateTask(); - - this.synchLanguage(); } deactivateTask() @@ -103,13 +100,7 @@ export default class CVAudioTask extends CVTask const clip = audioManager.getAudioClip(ins.activeId.value); const languageManager = this.activeDocument.setup.language; - - if(ins.language.changed) { - const newLanguage = ELanguageType[ELanguageType[ins.language.value]]; - - languageManager.addLanguage(newLanguage); // add in case this is a currently inactive language - languageManager.ins.language.setValue(newLanguage); - } + const activeLanguage = languageManager.ins.language.value; if (ins.create.changed) { const newId = Document.generateId(); @@ -138,8 +129,8 @@ export default class CVAudioTask extends CVTask if (clip && (ins.title.changed || ins.filepath.changed || ins.captionPath.changed)) { clip.name = ins.title.value; - clip.uris[ELanguageType[ins.language.value]] = ins.filepath.value; - clip.captionUris[ELanguageType[ins.language.value]] = ins.captionPath.value; + clip.uris[ELanguageType[activeLanguage]] = ins.filepath.value; + clip.captionUris[ELanguageType[activeLanguage]] = ins.captionPath.value; audioManager.updateAudioClip(clip.id); } if (ins.isNarration.changed) { @@ -172,27 +163,17 @@ export default class CVAudioTask extends CVTask const ins = this.ins; const audioManager = this.audioManager; const clip = audioManager.getAudioClip(ins.activeId.value); + const languageManager = this.activeDocument.setup.language; + const activeLanguage = languageManager.ins.language.value; ins.title.setValue(clip ? clip.name : "", true); - ins.filepath.setValue(clip ? clip.uris[ELanguageType[ins.language.value]] : "", true); - ins.captionPath.setValue(clip ? clip.captionUris[ELanguageType[ins.language.value]] : "", true); + ins.filepath.setValue(clip ? clip.uris[ELanguageType[activeLanguage]] : "", true); + ins.captionPath.setValue(clip ? clip.captionUris[ELanguageType[activeLanguage]] : "", true); ins.isNarration.setValue(clip ? this.audioManager.narrationId === clip.id : false, true); } protected onDocumentLanguageChange() { - this.synchLanguage(); this.onAudioChange(); } - - // Make sure this task language matches document - protected synchLanguage() { - const {ins} = this; - const languageManager = this.activeDocument.setup.language; - - if(ins.language.value !== languageManager.outs.language.value) - { - ins.language.setValue(languageManager.outs.language.value, true); - } - } } \ No newline at end of file diff --git a/source/client/ui/story/AudioTaskView.ts b/source/client/ui/story/AudioTaskView.ts index 67447ddb..450d7984 100644 --- a/source/client/ui/story/AudioTaskView.ts +++ b/source/client/ui/story/AudioTaskView.ts @@ -62,6 +62,7 @@ export default class AudioTaskView extends TaskView } const ins = this.task.ins; + const languageManager = this.activeDocument.setup.language; const narrationFlagClass = "sv-task-option-base-align"; const audio = this.task.audioManager; @@ -71,7 +72,7 @@ export default class AudioTaskView extends TaskView const detailView = audioElement ? html`
- +
From 6e606eb7de2ef817a506af80ba664eea9dec8304 Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 09:33:28 +0200 Subject: [PATCH 08/20] remove AnnotationTask's local language setting --- source/client/components/CVAnnotationsTask.ts | 28 ------------------- source/client/ui/story/AnnotationsTaskView.ts | 9 +++--- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/source/client/components/CVAnnotationsTask.ts b/source/client/components/CVAnnotationsTask.ts index 9a790173..b9d466f4 100644 --- a/source/client/components/CVAnnotationsTask.ts +++ b/source/client/components/CVAnnotationsTask.ts @@ -57,17 +57,12 @@ export default class CVAnnotationsTask extends CVTask protected static readonly ins = { mode: types.Enum("Mode", EAnnotationsTaskMode, EAnnotationsTaskMode.Off), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), audio: types.Option("Annotation.Audio", ["None"], 0), selection: types.Event("Annotation.Selection") }; - protected static readonly outs = { - language: types.Enum("Interface.Language", ELanguageType, ELanguageType[DEFAULT_LANGUAGE]), - }; ins = this.addInputs(CVAnnotationsTask.ins); - outs = this.addOutputs(CVAnnotationsTask.outs); private _activeAnnotations: CVAnnotationView = null; private _defaultScale = 1; @@ -104,7 +99,6 @@ export default class CVAnnotationsTask extends CVTask { this.startObserving(); super.activateTask(); - this.synchLanguage(); this.synchAudioOptions(); //this.selection.selectedComponents.on(CVAnnotationView, this.onSelectAnnotations, this); @@ -133,15 +127,6 @@ export default class CVAnnotationsTask extends CVTask this.emitUpdateEvent(); } - if(ins.language.changed) { - const newLanguage = ELanguageType[ELanguageType[ins.language.value]]; - - languageManager.addLanguage(newLanguage); // add in case this is a currently inactive language - languageManager.ins.language.setValue(newLanguage); - outs.language.setValue(newLanguage); - return true; - } - if(ins.audio.changed) { const audioManager = this.activeDocument.setup.audio; const id = ins.audio.value > 0 ? audioManager.getAudioList()[ins.audio.value - 1].id : ""; @@ -158,8 +143,6 @@ export default class CVAnnotationsTask extends CVTask this.setAudio(); } - this.synchLanguage(); - return true; } @@ -380,17 +363,6 @@ export default class CVAnnotationsTask extends CVTask } } - // Make sure this task language matches document - protected synchLanguage() { - const {ins} = this; - const languageManager = this.activeDocument.setup.language; - - if(ins.language.value !== languageManager.outs.language.value) - { - ins.language.setValue(languageManager.outs.language.value, true); - } - } - // Update audio options protected synchAudioOptions() { const audioManager = this.activeDocument.setup.audio; diff --git a/source/client/ui/story/AnnotationsTaskView.ts b/source/client/ui/story/AnnotationsTaskView.ts index 150fb2dd..a7294835 100644 --- a/source/client/ui/story/AnnotationsTaskView.ts +++ b/source/client/ui/story/AnnotationsTaskView.ts @@ -58,12 +58,12 @@ export default class AnnotationsTaskView extends TaskView this.sceneview = explorer.shadowRoot.querySelector(".sv-scene-view") as HTMLElement; this.task.on("update", this.onUpdate, this); - this.task.ins.language.on("value", this.onUpdate, this); + this.activeDocument.setup.language.ins.language.on("value", this.onUpdate, this); } protected disconnected() { - this.task.ins.language.off("value", this.onUpdate, this); + this.activeDocument.setup.language.ins.language.off("value", this.onUpdate, this); this.task.off("update", this.onUpdate, this); // set cursor to grab when leaving @@ -76,6 +76,7 @@ export default class AnnotationsTaskView extends TaskView { const node = this.activeNode; const annotations = node && node.getComponent(CVAnnotationView, true); + const languageManager = this.activeDocument.setup.language; if (!annotations) { // set cursor to grab @@ -118,7 +119,7 @@ export default class AnnotationsTaskView extends TaskView ${imagePropView} - +
@@ -142,7 +143,7 @@ export default class AnnotationsTaskView extends TaskView
-
${ELanguageStringType[DEFAULT_LANGUAGE]}
${ELanguageStringType[ELanguageType[this.task.ins.language.value] as TLanguageType]}
+
${ELanguageStringType[DEFAULT_LANGUAGE]}
${ELanguageStringType[ELanguageType[languageManager.ins.language.value] as TLanguageType]}
From 0804d8cc601e04442a968da68d476fe1959418e0 Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 09:39:58 +0200 Subject: [PATCH 09/20] remove ArticleTask's local language setting --- source/client/components/CVArticlesTask.ts | 23 ++-------------------- source/client/ui/story/ArticlesTaskView.ts | 5 +++-- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/source/client/components/CVArticlesTask.ts b/source/client/components/CVArticlesTask.ts index 81801da8..680e40b5 100644 --- a/source/client/components/CVArticlesTask.ts +++ b/source/client/components/CVArticlesTask.ts @@ -58,7 +58,6 @@ export default class CVArticlesTask extends CVTask lead: types.String("Article.Lead"), tags: types.String("Article.Tags"), uri: types.String("Article.URI"), - language: types.Option("Task.Language", Object.keys(ELanguageStringType).map(key => ELanguageStringType[key]), ELanguageStringType[ELanguageType[DEFAULT_LANGUAGE]]), }; protected static readonly outs = { @@ -98,7 +97,6 @@ export default class CVArticlesTask extends CVTask { this.startObserving(); super.activateTask(); - this.synchLanguage(); } deactivateTask() @@ -122,13 +120,6 @@ export default class CVArticlesTask extends CVTask } const languageManager = this.activeDocument.setup.language; - if(ins.language.changed) { - const newLanguage = ELanguageType[ELanguageType[ins.language.value]]; - - languageManager.addLanguage(newLanguage); // add in case this is a currently inactive language - languageManager.ins.language.setValue(newLanguage); - } - if (meta && ins.create.changed) { const article = new Article(); const defaultFolder = CVMediaManager.articleFolder; @@ -309,6 +300,7 @@ export default class CVArticlesTask extends CVTask const ins = this.ins; const outs = this.outs; const meta = this.meta; + const languageManager = this.activeDocument.setup.language; let article = this.reader.activeArticle; if (meta && article && meta.articles.getById(article.id)) { @@ -320,7 +312,7 @@ export default class CVArticlesTask extends CVTask // if we don't have a uri for this language, create one so that it is editable if(article.uri === undefined) { const defaultFolder = CVMediaManager.articleFolder; - article.uri = `${defaultFolder}/new-article-${article.id}-${ELanguageType[ins.language.value]}.html`; + article.uri = `${defaultFolder}/new-article-${article.id}-${ELanguageType[languageManager.ins.language.value]}.html`; this.ins.version.set(); } else { @@ -344,20 +336,9 @@ export default class CVArticlesTask extends CVTask const article = this.activeArticle; const {ins} = this; - this.synchLanguage(); this.onArticleChange(); } - // Make sure this task language matches document - protected synchLanguage() { - const {ins} = this; - const languageManager = this.activeDocument.setup.language; - - if(ins.language.value !== languageManager.outs.language.value) - { - ins.language.setValue(languageManager.outs.language.value, true); - } - } // Handle potential media manager name change protected onAssetRename(event: IAssetRenameEvent) { diff --git a/source/client/ui/story/ArticlesTaskView.ts b/source/client/ui/story/ArticlesTaskView.ts index c1af2a7c..017a0d21 100644 --- a/source/client/ui/story/ArticlesTaskView.ts +++ b/source/client/ui/story/ArticlesTaskView.ts @@ -49,6 +49,7 @@ export default class ArticlesTaskView extends TaskView const task = this.task; const articles = task.articles; const activeArticle = task.activeArticle; + const languageManager = this.activeDocument.setup.language; if (!articles) { return html`
Please select a scene or model node to edit its articles.
`; @@ -57,7 +58,7 @@ export default class ArticlesTaskView extends TaskView const props = task.ins; const detailView = activeArticle ? html`
- +
Title
Tags
@@ -81,7 +82,7 @@ export default class ArticlesTaskView extends TaskView
-
${ELanguageStringType[DEFAULT_LANGUAGE]}
${ELanguageStringType[ELanguageType[this.task.ins.language.value] as TLanguageType]}
+
${ELanguageStringType[DEFAULT_LANGUAGE]}
${ELanguageStringType[ELanguageType[languageManager.ins.language.value] as TLanguageType]}
From a0dd84469327779ddea8f73f367f709474036010 Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 09:54:57 +0200 Subject: [PATCH 10/20] remove CVLanguageManager.ins.language.value in favor of codeString and nameString where applicable --- source/client/components/CVArticlesTask.ts | 2 +- source/client/components/CVAudioTask.ts | 12 ++++++------ source/client/components/CVLanguageManager.ts | 6 +++++- source/client/ui/story/AnnotationsTaskView.ts | 4 ++-- source/client/ui/story/ArticlesTaskView.ts | 4 ++-- source/client/ui/story/TourPanel.ts | 2 +- source/client/ui/story/ToursTaskView.ts | 4 ++-- 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/source/client/components/CVArticlesTask.ts b/source/client/components/CVArticlesTask.ts index 680e40b5..56f7ea35 100644 --- a/source/client/components/CVArticlesTask.ts +++ b/source/client/components/CVArticlesTask.ts @@ -312,7 +312,7 @@ export default class CVArticlesTask extends CVTask // if we don't have a uri for this language, create one so that it is editable if(article.uri === undefined) { const defaultFolder = CVMediaManager.articleFolder; - article.uri = `${defaultFolder}/new-article-${article.id}-${ELanguageType[languageManager.ins.language.value]}.html`; + article.uri = `${defaultFolder}/new-article-${article.id}-${languageManager.codeString()}.html`; this.ins.version.set(); } else { diff --git a/source/client/components/CVAudioTask.ts b/source/client/components/CVAudioTask.ts index 473e3e95..8bcd55cf 100644 --- a/source/client/components/CVAudioTask.ts +++ b/source/client/components/CVAudioTask.ts @@ -100,7 +100,7 @@ export default class CVAudioTask extends CVTask const clip = audioManager.getAudioClip(ins.activeId.value); const languageManager = this.activeDocument.setup.language; - const activeLanguage = languageManager.ins.language.value; + const activeLanguage = languageManager.codeString(); if (ins.create.changed) { const newId = Document.generateId(); @@ -129,8 +129,8 @@ export default class CVAudioTask extends CVTask if (clip && (ins.title.changed || ins.filepath.changed || ins.captionPath.changed)) { clip.name = ins.title.value; - clip.uris[ELanguageType[activeLanguage]] = ins.filepath.value; - clip.captionUris[ELanguageType[activeLanguage]] = ins.captionPath.value; + clip.uris[activeLanguage] = ins.filepath.value; + clip.captionUris[activeLanguage] = ins.captionPath.value; audioManager.updateAudioClip(clip.id); } if (ins.isNarration.changed) { @@ -164,11 +164,11 @@ export default class CVAudioTask extends CVTask const audioManager = this.audioManager; const clip = audioManager.getAudioClip(ins.activeId.value); const languageManager = this.activeDocument.setup.language; - const activeLanguage = languageManager.ins.language.value; + const activeLanguage = languageManager.codeString(); ins.title.setValue(clip ? clip.name : "", true); - ins.filepath.setValue(clip ? clip.uris[ELanguageType[activeLanguage]] : "", true); - ins.captionPath.setValue(clip ? clip.captionUris[ELanguageType[activeLanguage]] : "", true); + ins.filepath.setValue(clip ? clip.uris[activeLanguage] : "", true); + ins.captionPath.setValue(clip ? clip.captionUris[activeLanguage] : "", true); ins.isNarration.setValue(clip ? this.audioManager.narrationId === clip.id : false, true); } diff --git a/source/client/components/CVLanguageManager.ts b/source/client/components/CVLanguageManager.ts index e7a6fee1..5b50ac83 100644 --- a/source/client/components/CVLanguageManager.ts +++ b/source/client/components/CVLanguageManager.ts @@ -75,7 +75,11 @@ export default class CVLanguageManager extends Component return this._activeLanguages; } - nameString() + /** + * + * @returns Full text string of the currently selected language + */ + nameString() :string { return ELanguageStringType[ELanguageType[this.ins.language.value]]; } diff --git a/source/client/ui/story/AnnotationsTaskView.ts b/source/client/ui/story/AnnotationsTaskView.ts index a7294835..044c67e0 100644 --- a/source/client/ui/story/AnnotationsTaskView.ts +++ b/source/client/ui/story/AnnotationsTaskView.ts @@ -32,7 +32,7 @@ import { ISelectAnnotationEvent } from "./AnnotationList"; import CVAnnotationView from "../../components/CVAnnotationView"; import CVAnnotationsTask, { EAnnotationsTaskMode } from "../../components/CVAnnotationsTask"; import { TaskView } from "../../components/CVTask"; -import { ELanguageStringType, ELanguageType, TLanguageType, DEFAULT_LANGUAGE } from "client/schema/common"; +import { ELanguageStringType, DEFAULT_LANGUAGE } from "client/schema/common"; import sanitizeHtml from 'sanitize-html'; import CVMediaManager from "client/components/CVMediaManager"; @@ -143,7 +143,7 @@ export default class AnnotationsTaskView extends TaskView
-
${ELanguageStringType[DEFAULT_LANGUAGE]}
${ELanguageStringType[ELanguageType[languageManager.ins.language.value] as TLanguageType]}
+
${ELanguageStringType[DEFAULT_LANGUAGE]}
${languageManager.nameString()}
diff --git a/source/client/ui/story/ArticlesTaskView.ts b/source/client/ui/story/ArticlesTaskView.ts index 017a0d21..4de3887b 100644 --- a/source/client/ui/story/ArticlesTaskView.ts +++ b/source/client/ui/story/ArticlesTaskView.ts @@ -25,7 +25,7 @@ import Article from "../../models/Article"; import CVArticlesTask from "../../components/CVArticlesTask"; import { TaskView } from "../../components/CVTask"; -import { ELanguageStringType, ELanguageType, TLanguageType, DEFAULT_LANGUAGE } from "client/schema/common"; +import { ELanguageStringType, DEFAULT_LANGUAGE } from "client/schema/common"; //////////////////////////////////////////////////////////////////////////////// @@ -82,7 +82,7 @@ export default class ArticlesTaskView extends TaskView
-
${ELanguageStringType[DEFAULT_LANGUAGE]}
${ELanguageStringType[ELanguageType[languageManager.ins.language.value] as TLanguageType]}
+
${ELanguageStringType[DEFAULT_LANGUAGE]}
${languageManager.nameString()}
diff --git a/source/client/ui/story/TourPanel.ts b/source/client/ui/story/TourPanel.ts index 8371b47e..84ff1ae2 100644 --- a/source/client/ui/story/TourPanel.ts +++ b/source/client/ui/story/TourPanel.ts @@ -123,7 +123,7 @@ export default class TourPanel extends DocumentView this.stateTable.rows = tours.activeSteps.map(step => { const state = machine.getState(step.id); return { - title: step.titles[ELanguageType[languageManager.ins.language.value]] || "undefined", + title: step.titles[languageManager.codeString()] || "undefined", curve: EEasingCurve[state.curve], duration: state.duration.toFixed(1) + "s", threshold: (state.threshold * 100).toFixed(0) + "%", diff --git a/source/client/ui/story/ToursTaskView.ts b/source/client/ui/story/ToursTaskView.ts index 671a9d4a..34890ddd 100644 --- a/source/client/ui/story/ToursTaskView.ts +++ b/source/client/ui/story/ToursTaskView.ts @@ -27,7 +27,7 @@ import { ILineEditChangeEvent } from "@ff/ui/LineEdit"; import CVDocument from "../../components/CVDocument"; import { IButtonClickEvent } from "@ff/ui/Button"; -import { ELanguageType, DEFAULT_LANGUAGE, ELanguageStringType, TLanguageType } from "client/schema/common"; +import { ELanguageType, DEFAULT_LANGUAGE, ELanguageStringType } from "client/schema/common"; //////////////////////////////////////////////////////////////////////////////// @@ -99,7 +99,7 @@ export default class ToursTaskView extends TaskView
-
${ELanguageStringType[DEFAULT_LANGUAGE]}
${ELanguageStringType[ELanguageType[languageManager.ins.language.value] as TLanguageType]}
+
${ELanguageStringType[DEFAULT_LANGUAGE]}
${languageManager.nameString()}
From 6a9efba120ecb765d98af901609cd41f1b5c0a1d Mon Sep 17 00:00:00 2001 From: Jamie Cope Date: Tue, 11 Jun 2024 11:06:03 -0400 Subject: [PATCH 11/20] Fix for #279 null reference issue with React --- source/client/components/CVOrbitNavigation.ts | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/source/client/components/CVOrbitNavigation.ts b/source/client/components/CVOrbitNavigation.ts index 23e9e983..8befc70b 100644 --- a/source/client/components/CVOrbitNavigation.ts +++ b/source/client/components/CVOrbitNavigation.ts @@ -275,24 +275,26 @@ export default class CVOrbitNavigation extends CObject3D else { const prompt = this.arManager.shadowRoot.getElementById("prompt") as HTMLElement; - // prompt rotation function - const pause = 2.0; - const period = 1.5; - const cycle = 2.0 * period; - const fadeLength = 0.2 * period; - let deltaMod = delta % (cycle + pause); - if(deltaMod > cycle && deltaMod < cycle + pause) { - prompt.style.opacity = deltaMod < cycle + fadeLength ? `${1.0 - ((deltaMod - cycle) / fadeLength)}` : "0.0"; - deltaMod = 0.0; - } - else if(deltaMod < fadeLength) { - prompt.style.opacity = deltaMod < fadeLength ? `${deltaMod / fadeLength}` : "1.0"; + if(prompt) { + // prompt rotation function + const pause = 2.0; + const period = 1.5; + const cycle = 2.0 * period; + const fadeLength = 0.2 * period; + let deltaMod = delta % (cycle + pause); + if(deltaMod > cycle && deltaMod < cycle + pause) { + prompt.style.opacity = deltaMod < cycle + fadeLength ? `${1.0 - ((deltaMod - cycle) / fadeLength)}` : "0.0"; + deltaMod = 0.0; + } + else if(deltaMod < fadeLength) { + prompt.style.opacity = deltaMod < fadeLength ? `${deltaMod / fadeLength}` : "1.0"; + } + + const promptOffset = Math.sin((deltaMod/period) * Math.PI) * 20.0; + controller.orbit.y = this._initYOrbit + promptOffset; + + prompt.style.transform = `translateX(${-4*promptOffset}px)`; } - - const promptOffset = Math.sin((deltaMod/period) * Math.PI) * 20.0; - controller.orbit.y = this._initYOrbit + promptOffset; - - prompt.style.transform = `translateX(${-4*promptOffset}px)`; } } From c368f0713cdcf56b75e7ae73820eb86228cc5f5d Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 15:05:38 +0200 Subject: [PATCH 12/20] fix styles for button property options. handle properties with multiple selection fixup: index for buttons and options change tracking --- source/client/ui/PropertyOptions.ts | 45 ++++++++++++++++++++++----- source/client/ui/explorer/styles.scss | 13 ++++++++ 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/source/client/ui/PropertyOptions.ts b/source/client/ui/PropertyOptions.ts index 8007bfbf..4492f196 100644 --- a/source/client/ui/PropertyOptions.ts +++ b/source/client/ui/PropertyOptions.ts @@ -67,6 +67,7 @@ export default class PropertyOptions extends CustomElement } if (this.property) { this.property.on("value", this.onUpdate, this); + this.property.on("change", this.onUpdate, this); } } @@ -92,16 +93,19 @@ export default class PropertyOptions extends CustomElement let optionsList; if (indexMap) { optionsList = indexMap.map(index => - html``); + html``); } else { optionsList = options.map((option, index) => - html``) + option? html``:null) } return html` - { + console.debug("Select value : ", e.target.value); + this.property.setValue(e.target.value) + }}> ${optionsList} `; @@ -120,22 +124,47 @@ export default class PropertyOptions extends CustomElement let buttons; if (indexMap) { buttons = indexMap.map(index => - html` + html` `); } else { buttons = options.map((option, index) => - html` - `) + option?html` + `:null) } - return html`
this.onKeyDown(e)} title=${name} class="sv-options">${buttons}
`; + return html` + +
this.onKeyDown(e)} title=${name} class="sv-options"> + ${buttons} +
`; } + + isSelected(index: number){ + if(this.property.isMulti()){ + return this.property.value.includes(index); + }else{ + return this.property.value == index; + } + } + + protected onButtonClick(event: IButtonClickEvent) { const value = event.target.index; - this.property.setValue(value); + if(this.property.isMulti()){ + let selection = this.property.value.slice(); + let valueIndex = selection.indexOf(value); + if(valueIndex !== -1){ + selection = selection.filter(v => v !== value); + }else{ + selection.push(value); + } + this.property.setValue(selection); + }else{ + this.property.setValue(value); + } } protected onKeyDown(e: KeyboardEvent) diff --git a/source/client/ui/explorer/styles.scss b/source/client/ui/explorer/styles.scss index d8416961..52cb1b6e 100644 --- a/source/client/ui/explorer/styles.scss +++ b/source/client/ui/explorer/styles.scss @@ -1315,6 +1315,19 @@ $tour-entry-indent: 12px; } } } + + &.sv-property-options{ + .sv-options-buttons{ + display: flex; + flex-wrap: wrap; + justify-content: center; + padding: 2px 0; + gap: 2px; + .ff-button.ff-control{ + flex: 0 1 auto; + } + } + } } From 706c7502aa6e9aa364114fdd271090c9495e2efb Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 15:11:13 +0200 Subject: [PATCH 13/20] fix structure of CollectionPanel that wasn't visually connecting with the menu like the other tabs --- source/client/ui/story/CollectionPanel.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/client/ui/story/CollectionPanel.ts b/source/client/ui/story/CollectionPanel.ts index 1d798dd7..cd775984 100644 --- a/source/client/ui/story/CollectionPanel.ts +++ b/source/client/ui/story/CollectionPanel.ts @@ -40,7 +40,8 @@ export default class CollectionPanel extends DocumentView { const languageManager = this.activeDocument.setup.language; - return html`
+ return html`
+
Collection
@@ -50,7 +51,8 @@ export default class CollectionPanel extends DocumentView
Intro
-
`; +
+
`; } protected onTextEdit(event: ILineEditChangeEvent) From d1e5dbe49494733ff8e85f936e307e7b20a40f0d Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Tue, 11 Jun 2024 10:27:11 +0200 Subject: [PATCH 14/20] properly set language on annotations initialization --- source/client/components/CVAnnotationView.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/client/components/CVAnnotationView.ts b/source/client/components/CVAnnotationView.ts index de5c1bcd..cc5399a7 100755 --- a/source/client/components/CVAnnotationView.ts +++ b/source/client/components/CVAnnotationView.ts @@ -438,7 +438,12 @@ export default class CVAnnotationView extends CObject3D fromData(data: IAnnotation[]) { - data.forEach(annotationJson => this.addAnnotation(new Annotation(annotationJson))); + const language = this.language.outs.language.value; + data.forEach(annotationJson => { + let a = new Annotation(annotationJson); + a.language = language; + this.addAnnotation(a); + }); this.emit({ type: "tag-update" }); } From d051c560628ebee0d011e83bb210c148463bf0f4 Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Fri, 7 Jun 2024 15:03:45 +0200 Subject: [PATCH 15/20] fix a race condition in CVLanguageManager where a language set by the lang parameter would get reset on document load. properly update activeLanguages list from CVMeta. --- source/client/components/CVLanguageManager.ts | 20 +++++++++---------- source/client/components/CVMeta.ts | 3 +++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/source/client/components/CVLanguageManager.ts b/source/client/components/CVLanguageManager.ts index 5b50ac83..f2e99fc0 100644 --- a/source/client/components/CVLanguageManager.ts +++ b/source/client/components/CVLanguageManager.ts @@ -40,7 +40,7 @@ export default class CVLanguageManager extends Component static readonly text: string = "Language"; static readonly icon: string = ""; - private _activeLanguages: ILanguageOption[] = []; + private _activeLanguages: {[key in TLanguageType]?: ILanguageOption} = {}; private _translations: ITranslation = {}; static readonly isSystemSingleton = true; @@ -72,7 +72,7 @@ export default class CVLanguageManager extends Component return this.getMainComponent(CVAssetReader); } get activeLanguages() { - return this._activeLanguages; + return Object.values(this._activeLanguages); } /** @@ -98,13 +98,14 @@ export default class CVLanguageManager extends Component { const { ins, outs } = this; - if(this.activeLanguages.length == 0) { + if(this.activeLanguages.length == 0 && ins.language.value == outs.language.value) { this.addLanguage(outs.language.value); //return; } if (ins.language.changed && ins.language.value != outs.language.value) { const newLanguage = ins.language.value; + this.addLanguage(newLanguage); this.assetReader.getSystemJSON("language/string.resources." + ELanguageType[this.ins.language.value].toLowerCase() + ".json").then( json => { this._translations = json; this.updateLanguage(newLanguage); @@ -121,10 +122,11 @@ export default class CVLanguageManager extends Component const { ins, outs } = this; data = data || {} as ILanguage; - const language = ELanguageType[data.language || "EN"]; + const language = ELanguageType[data.language || "EN"] ?? ELanguageType[DEFAULT_LANGUAGE]; - if(language != outs.language.value && ins.language.value === outs.language.value) { - ins.language.setValue(isFinite(language) ? language : ELanguageType[DEFAULT_LANGUAGE]); + //If language has already been set, don't overwrite it. + if(ins.language.value < 0) { + ins.language.setValue(language); } } @@ -138,11 +140,7 @@ export default class CVLanguageManager extends Component } addLanguage(language: ELanguageType) { - const exists = this._activeLanguages.find(element => element.id === language) - - if(!exists) { - this._activeLanguages.push({ id: language, name: ELanguageStringType[ELanguageType[language]] }); - } + this._activeLanguages[ELanguageType[language]] ??= { id: language, name: ELanguageStringType[ELanguageType[language]] }; } getLocalizedString(text: string): string diff --git a/source/client/components/CVMeta.ts b/source/client/components/CVMeta.ts index 4a5dfb02..207b464d 100644 --- a/source/client/components/CVMeta.ts +++ b/source/client/components/CVMeta.ts @@ -59,6 +59,9 @@ export default class CVMeta extends Component if (data.collection) { this.collection.dictionary = data.collection; + Object.keys(this.collection.get("titles")).forEach( key => { + this.language.addLanguage(ELanguageType[key]); + }); } if (data.process) { this.process.dictionary = data.process; From 3cbbeb574b9dc6aae7444f55e982747c98f8648d Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Tue, 25 Jun 2024 17:40:35 +0200 Subject: [PATCH 16/20] use the live directive for sv-property-options select --- source/client/ui/PropertyOptions.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/client/ui/PropertyOptions.ts b/source/client/ui/PropertyOptions.ts index 4492f196..eeba45f3 100644 --- a/source/client/ui/PropertyOptions.ts +++ b/source/client/ui/PropertyOptions.ts @@ -14,6 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +import {live} from "lit-html/directives/live"; import Property from "@ff/graph/Property"; import CustomElement, { customElement, property, PropertyValues, html } from "@ff/ui/CustomElement"; @@ -64,6 +66,7 @@ export default class PropertyOptions extends CustomElement const property = changedProperties.get("property") as Property; if (property) { property.off("value", this.onUpdate, this); + property.off("change", this.onUpdate, this); } if (this.property) { this.property.on("value", this.onUpdate, this); @@ -102,8 +105,7 @@ export default class PropertyOptions extends CustomElement return html` - { this.property.setValue(e.target.value) }}> ${optionsList} From 1c5db8dba32eb70e9db89f6d063252e5fcbf7dd1 Mon Sep 17 00:00:00 2001 From: Jamie Cope Date: Wed, 26 Jun 2024 08:26:40 -0400 Subject: [PATCH 17/20] Style margin update --- source/client/ui/story/styles.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/client/ui/story/styles.scss b/source/client/ui/story/styles.scss index c1efcd97..8612f9d4 100644 --- a/source/client/ui/story/styles.scss +++ b/source/client/ui/story/styles.scss @@ -231,7 +231,7 @@ $color-component-meta-light: #d9d998; padding: 6px; .sv-indent { - margin-left: 15px; + margin: 2px 2px 2px 15px; } } From ec3309bb7a7aef733e458eaa103b56f5b1a9a84c Mon Sep 17 00:00:00 2001 From: Jamie Cope Date: Wed, 26 Jun 2024 10:35:51 -0400 Subject: [PATCH 18/20] Intro panel cleanup and bugfix --- source/client/components/CVDocument.ts | 2 +- source/client/ui/explorer/ChromeView.ts | 20 ++++++-------------- source/client/ui/story/CollectionPanel.ts | 2 ++ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/source/client/components/CVDocument.ts b/source/client/components/CVDocument.ts index bbcace70..d06ff069 100755 --- a/source/client/components/CVDocument.ts +++ b/source/client/components/CVDocument.ts @@ -328,7 +328,7 @@ export default class CVDocument extends CRenderGraph const newTitle = this.titles[ELanguageType[language.outs.language.value]]; this.ins.title.setValue(newTitle); - const newIntro = this.intros[ELanguageType[language.outs.language.value]]; + const newIntro = this.intros[ELanguageType[language.outs.language.value]] || ""; this.ins.intro.setValue(newIntro); } diff --git a/source/client/ui/explorer/ChromeView.ts b/source/client/ui/explorer/ChromeView.ts index b51a2dc6..4499cc5c 100644 --- a/source/client/ui/explorer/ChromeView.ts +++ b/source/client/ui/explorer/ChromeView.ts @@ -130,11 +130,13 @@ export default class ChromeView extends DocumentView this.activeDocument.setup.tours.outs.ending.setValue(false); const introText = this.activeDocument.outs.intro.value; - if(this.needsSplash && introText && introText.length > 0) { + if(introText) { + if(this.needsSplash && introText.length > 0) { + SplashScreen.show(this, this.activeDocument.setup.language, introText).then(() => { + (this.getRootNode() as ShadowRoot).getElementById("sv-scene").focus(); + }); + } this.needsSplash = false; - SplashScreen.show(this, this.activeDocument.setup.language, introText).then(() => { - (this.getRootNode() as ShadowRoot).getElementById("sv-scene").focus(); - }); } if (!interfaceVisible) { @@ -183,16 +185,6 @@ export default class ChromeView extends DocumentView
`; } - protected firstUpdated(_changedProperties: Map): void { - const introText = this.activeDocument.outs.intro.value; - if(this.needsSplash && introText.length > 0) { - this.needsSplash = false; - SplashScreen.show(this, this.activeDocument.setup.language, introText).then(() => { - //(this.querySelector("#main-help") as HTMLElement).focus(); - }); - } - } - protected onSelectTour(event: ITourMenuSelectEvent) { const tours = this.activeDocument.setup.tours; diff --git a/source/client/ui/story/CollectionPanel.ts b/source/client/ui/story/CollectionPanel.ts index 6741e736..52d73517 100644 --- a/source/client/ui/story/CollectionPanel.ts +++ b/source/client/ui/story/CollectionPanel.ts @@ -88,9 +88,11 @@ export default class CollectionPanel extends DocumentView if (previous) { previous.setup.language.outs.language.off("value", this.onUpdate, this); previous.outs.title.off("value", this.onUpdate, this); + previous.outs.intro.off("value", this.onUpdate, this); } if (next) { next.outs.title.on("value", this.onUpdate, this); + next.outs.intro.on("value", this.onUpdate, this); next.setup.language.outs.language.on("value", this.onUpdate, this); } } From ca1e8ea3e8feea8843b165f71dbd7acc6d8a81a7 Mon Sep 17 00:00:00 2001 From: Jamie Cope Date: Wed, 26 Jun 2024 11:48:37 -0400 Subject: [PATCH 19/20] Version update --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e328346f..ffc2308e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "voyager", - "version": "0.39.0", + "version": "0.41.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "voyager", - "version": "0.39.0", + "version": "0.41.0", "license": "Apache-2.0", "dependencies": { "ajv": "^8.6.2", diff --git a/package.json b/package.json index 64bf70cd..aaa2ebad 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "voyager", - "version": "0.41.0", + "version": "0.42.0", "description": "Smithsonian DPO Voyager - 3D Explorer and Tool Suite", "scripts": { "start": "npm run server", From 49ed80c7e119e4b879dccfa08d9f3ae880928503 Mon Sep 17 00:00:00 2001 From: Jamie Cope Date: Thu, 27 Jun 2024 14:08:13 -0400 Subject: [PATCH 20/20] AudioManager bug fix to correctly init files for all languages on load --- source/client/components/CVAudioManager.ts | 46 +++++++++++----------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/source/client/components/CVAudioManager.ts b/source/client/components/CVAudioManager.ts index 8eed9cf6..0f65f0b7 100644 --- a/source/client/components/CVAudioManager.ts +++ b/source/client/components/CVAudioManager.ts @@ -166,29 +166,31 @@ export default class CVAudioManager extends Component } else { const clip = this.audioClips[id]; - const uri = clip.uris[language]; - if(uri) { - const absUri = this.assetManager.getAssetUrl(uri); - clip.durations[language] = "pending"; - - const audioContext = new (window.AudioContext || window.webkitAudioContext)(); - const request = new XMLHttpRequest(); - request.open('GET', absUri, true); - request.responseType = 'arraybuffer'; - request.onload = () => { - const blob = new Blob([request.response], { type: "audio/mpeg" }); - const url = window.URL.createObjectURL(blob); - this._audioMap[uri] = url; - audioContext.decodeAudioData(request.response, - (buffer) => { - let duration = buffer.duration; - clip.durations[language] = duration.toString(); - this.getPlayerById(id).requestUpdate(); - } - ) + Object.keys(clip.uris).forEach(language => { + const uri = clip.uris[language]; + if(uri) { + const absUri = this.assetManager.getAssetUrl(uri); + clip.durations[language] = "pending"; + + const audioContext = new (window.AudioContext || window.webkitAudioContext)(); + const request = new XMLHttpRequest(); + request.open('GET', absUri, true); + request.responseType = 'arraybuffer'; + request.onload = () => { + const blob = new Blob([request.response], { type: "audio/mpeg" }); + const url = window.URL.createObjectURL(blob); + this._audioMap[uri] = url; + audioContext.decodeAudioData(request.response, + (buffer) => { + let duration = buffer.duration; + clip.durations[language] = duration.toString(); + this.getPlayerById(id).requestUpdate(); + } + ) + } + request.send(); } - request.send(); - } + }); return "pending"; }