diff --git a/src/components/chart-editor.vue b/src/components/chart-editor.vue
index 7cfed828..b748ae75 100644
--- a/src/components/chart-editor.vue
+++ b/src/components/chart-editor.vue
@@ -296,7 +296,7 @@ export default class ChartEditorV extends Vue {
onChartsEdited(): void {
this.edited = true;
- this.$emit('slide-edit');
+ this.$emit('slide-edit', this.chartConfigs.length !== 0);
}
}
diff --git a/src/components/dynamic-editor.vue b/src/components/dynamic-editor.vue
index 9d2e6fd2..2c31b8d3 100644
--- a/src/components/dynamic-editor.vue
+++ b/src/components/dynamic-editor.vue
@@ -95,6 +95,7 @@
import { Options, Prop, Vue } from 'vue-property-decorator';
import {
BasePanel,
+ BaseStartingConfig,
ChartPanel,
ConfigFileStructure,
DefaultConfigs,
@@ -146,45 +147,7 @@ export default class DynamicEditorV extends Vue {
video: 'video-editor'
};
- startingConfig: DefaultConfigs = {
- text: {
- type: PanelType.Text,
- title: '',
- content: ''
- },
- dynamic: {
- type: PanelType.Dynamic,
- title: '',
- titleTag: '',
- content: '',
- children: []
- },
- slideshow: {
- type: PanelType.Slideshow,
- items: [],
- userCreated: true
- },
- image: {
- type: PanelType.Image,
- src: ''
- },
- chart: {
- type: PanelType.Chart,
- src: ''
- },
- map: {
- type: PanelType.Map,
- config: '',
- title: '',
- scrollguard: false
- },
- video: {
- type: PanelType.Video,
- title: '',
- videoType: '',
- src: ''
- }
- };
+ startingConfig: DefaultConfigs = JSON.parse(JSON.stringify(BaseStartingConfig));
editingStatus = 'text';
editingSlide = -1;
diff --git a/src/components/image-editor.vue b/src/components/image-editor.vue
index 6d30756a..9e1e27d3 100644
--- a/src/components/image-editor.vue
+++ b/src/components/image-editor.vue
@@ -293,7 +293,7 @@ export default class ImageEditorV extends Vue {
onImagesEdited(): void {
this.edited = true;
- this.$emit('slide-edit');
+ this.$emit('slide-edit', this.imagePreviews.length !== 0);
}
}
diff --git a/src/components/slide-editor.vue b/src/components/slide-editor.vue
index 2f49f366..a0a19ad8 100644
--- a/src/components/slide-editor.vue
+++ b/src/components/slide-editor.vue
@@ -34,7 +34,13 @@
class="editor-input rounded-none cursor-pointer w-4 h-4"
v-model="rightOnly"
:disabled="rightOnly && determineEditorType(currentSlide.panel[panelIndex]) === 'dynamic'"
- @change.stop="$vfm.open(`right-only-${slideIndex}`)"
+ @change.stop="
+ if (currentSlide.panel.length > 1 && panelModified(currentSlide.panel[0])) {
+ $vfm.open(`right-only-${slideIndex}`);
+ } else {
+ toggleRightOnly();
+ }
+ "
/>
{{ $t('editor.slides.centerSlide') }}
panelModified(panel)))
+ ) {
+ $vfm.open(`change-slide-${slideIndex}`);
+ } else {
+ changePanelType(determineEditorType(currentSlide.panel[panelIndex]), newType);
+ toggleCenterPanel();
+ toggleCenterSlide();
+ }
"
:value="determineEditorType(currentSlide.panel[panelIndex])"
>
@@ -269,7 +285,15 @@
:sourceCounts="sourceCounts"
:centerSlide="centerSlide"
:dynamicSelected="dynamicSelected"
- @slide-edit="$emit('slide-edit')"
+ @slide-edit="(changedFromDefault: boolean = true) => {
+ $emit('slide-edit');
+
+ // changedFromDefault should hold a boolean indicating whether the panel is actually modified
+ // (different from initial state). Only needed for some multimedia editors; text editors
+ // write directly to currentSlide constantly, which is handled by panelModified().
+ currentSlide.panel[panelIndex].modified = changedFromDefault || undefined;
+ }
+ "
v-else
>
@@ -308,6 +332,7 @@
import { Options, Prop, Vue, Watch } from 'vue-property-decorator';
import {
BasePanel,
+ BaseStartingConfig,
ChartPanel,
ConfigFileStructure,
DefaultConfigs,
@@ -334,6 +359,7 @@ import SlideshowEditorV from './slideshow-editor.vue';
import LoadingPageV from './helpers/loading-page.vue';
import DynamicEditorV from './dynamic-editor.vue';
import ConfirmationModalV from './helpers/confirmation-modal.vue';
+import { toRaw } from 'vue';
@Options({
components: {
@@ -383,13 +409,21 @@ export default class SlideEditorV extends Vue {
this.currentSlide ? (this.rightOnly = this.currentSlide.panel.length === 1) : false;
}
- changePanelType(prevType: string, newType: string): void {
- const startingConfig: DefaultConfigs = {
- text: {
- type: PanelType.Text,
- title: '',
- content: ''
- },
+ /**
+ * Determines whether a given panel has been modified from the default configuration of its type.
+ * Note that some editors (e.g. text) write directly to currentSlide after each change,
+ * while other editors (e.g. image) do not. The first type is handled completely in
+ * panelModified; the second type requires you to set `panel.modified` for the given panel beforehand,
+ * indicating whether changes have been made from the specific editor sub-component (see
+ * ``'s `@slide-edit` event handler).
+ * @param {BasePanel} panel The panel to analyze.
+ * @returns {boolean} Whether panel has been modified.
+ */
+ panelModified(panel: BasePanel): boolean {
+ const prevType = this.currentSlide.panel[this.panelIndex].type;
+
+ let startingConfig = {
+ ...JSON.parse(JSON.stringify(BaseStartingConfig)),
dynamic: {
type: PanelType.Dynamic,
title:
@@ -403,30 +437,42 @@ export default class SlideEditorV extends Vue {
: '',
children: []
},
- slideshow: {
- type: PanelType.Slideshow,
- items: [],
- userCreated: true
- },
- image: {
- type: PanelType.Image,
- src: ''
- },
- chart: {
- type: PanelType.Chart,
- src: ''
- },
map: {
type: PanelType.Map,
- config: '',
+ config: `${this.configFileStructure.uuid}/ramp-config/${
+ this.configFileStructure.uuid
+ }-map-${this.getNumberOfMaps()}.json`,
title: '',
scrollguard: false
- },
- video: {
- type: PanelType.Video,
- title: '',
- videoType: '',
- src: ''
+ }
+ };
+
+ const oldStartingConfig = startingConfig[panel.type as keyof DefaultConfigs];
+
+ let newConfig = Object.assign({}, toRaw(panel));
+ newConfig.customStyles = newConfig.customStyles || undefined;
+
+ return (
+ JSON.stringify(oldStartingConfig) !== JSON.stringify(newConfig) ||
+ this.currentSlide.panel[this.panelIndex].modified === true
+ );
+ }
+
+ changePanelType(prevType: string, newType: string): void {
+ let startingConfig = {
+ ...JSON.parse(JSON.stringify(BaseStartingConfig)),
+ dynamic: {
+ type: PanelType.Dynamic,
+ title:
+ this.currentSlide.panel[0] && prevType === 'text'
+ ? (this.currentSlide.panel[0] as TextPanel).title
+ : '',
+ titleTag: '',
+ content:
+ this.currentSlide.panel[0] && prevType === 'text'
+ ? (this.currentSlide.panel[0] as TextPanel).content
+ : '',
+ children: []
}
};
@@ -628,6 +674,14 @@ export default class SlideEditorV extends Vue {
}
}
}
+
+ getNumberOfMaps(): number {
+ let n = 0;
+ this.configFileStructure.rampConfig.forEach((f) => {
+ n += 1;
+ });
+ return n;
+ }
}
diff --git a/src/components/slideshow-editor.vue b/src/components/slideshow-editor.vue
index 394a0a63..7216eedc 100644
--- a/src/components/slideshow-editor.vue
+++ b/src/components/slideshow-editor.vue
@@ -124,6 +124,7 @@
import { Options, Prop, Vue } from 'vue-property-decorator';
import {
BasePanel,
+ BaseStartingConfig,
ChartPanel,
ConfigFileStructure,
DefaultConfigs,
@@ -163,43 +164,17 @@ export default class SlideshowEditorV extends Vue {
video: 'video-editor'
};
- // TODO: we use this and a few other functions (updating source counts, etc.) in multiple places. We should probably look in to putting this somewhere else.
startingConfig: DefaultConfigs = {
- text: {
- type: PanelType.Text,
- title: '',
- content: ''
- },
- dynamic: {
- type: PanelType.Dynamic,
- title: '',
- titleTag: '',
- content: '',
- children: []
- },
+ ...JSON.parse(JSON.stringify(BaseStartingConfig)),
slideshow: {
type: PanelType.Slideshow,
items: []
},
- chart: {
- type: PanelType.Chart,
- src: ''
- },
- image: {
- type: PanelType.Image,
- src: ''
- },
map: {
type: PanelType.Map,
config: '',
title: '',
scrollguard: true // default to ON for slideshows. Allows users to use the cursor to switch slides.
- },
- video: {
- type: PanelType.Video,
- title: '',
- videoType: '',
- src: ''
}
};
@@ -289,7 +264,7 @@ export default class SlideshowEditorV extends Vue {
(this.$refs.slideEditor as ImageEditorV | ChartEditorV).saveChanges();
if (itemConfig.type === PanelType.Map) {
- this.$emit('slide-edit');
+ this.$emit('slide-edit', false);
}
}
}
diff --git a/src/components/video-editor.vue b/src/components/video-editor.vue
index 7baf03b8..0e048f0f 100644
--- a/src/components/video-editor.vue
+++ b/src/components/video-editor.vue
@@ -273,7 +273,10 @@ export default class VideoEditorV extends Vue {
onVideoEdited(): void {
this.edited = true;
- this.$emit('slide-edit');
+ this.$emit(
+ 'slide-edit',
+ (this.videoPreview?.videoType || this.videoPreview?.title?.length) ? true : false
+ );
}
}
diff --git a/src/definitions.ts b/src/definitions.ts
index 3adde3d2..d045063e 100644
--- a/src/definitions.ts
+++ b/src/definitions.ts
@@ -156,6 +156,7 @@ export interface BasePanel {
type: string;
width?: number;
customStyles?: string;
+ modified?: boolean;
}
export interface TextPanel extends BasePanel {
@@ -282,3 +283,43 @@ export interface DefaultConfigs {
video: VideoPanel;
image: ImagePanel;
}
+
+export const BaseStartingConfig: DefaultConfigs = {
+ text: {
+ type: PanelType.Text,
+ title: '',
+ content: ''
+ },
+ dynamic: {
+ type: PanelType.Dynamic,
+ title: '',
+ titleTag: '',
+ content: '',
+ children: []
+ },
+ slideshow: {
+ type: PanelType.Slideshow,
+ items: [],
+ userCreated: true
+ },
+ image: {
+ type: PanelType.Image,
+ src: ''
+ },
+ chart: {
+ type: PanelType.Chart,
+ src: ''
+ },
+ map: {
+ type: PanelType.Map,
+ config: '',
+ title: '',
+ scrollguard: false
+ },
+ video: {
+ type: PanelType.Video,
+ title: '',
+ videoType: '',
+ src: ''
+ }
+};