diff --git a/entry_types/scrolled/config/locales/new/hotspots.de.yml b/entry_types/scrolled/config/locales/new/hotspots.de.yml
index 0b2003950..b0d80a9cb 100644
--- a/entry_types/scrolled/config/locales/new/hotspots.de.yml
+++ b/entry_types/scrolled/config/locales/new/hotspots.de.yml
@@ -31,6 +31,19 @@ de:
values:
indicator: Am Indikator
area: Am Bereich
+ tooltipMaxWidth:
+ label: Tooltip-Maximalbreite
+ values:
+ medium: "Mittel"
+ veryNarrow: Sehr schmal
+ narrow: Schmal
+ wide: Breit
+ tooltipTextAlign:
+ label: Textausrichtung in Tooltip
+ values:
+ left: Links
+ center: Zentriert
+ right: Rechts
color:
label: Farbe
activeImage:
@@ -51,6 +64,13 @@ de:
values:
indicator: Am Indikator
area: Am Bereich
+ portraitTooltipMaxWidth:
+ label: Tooltip-Maximalbreite (Hochkant)
+ values:
+ medium: "Mittel"
+ narrow: Schmal
+ veryNarrow: Sehr schmal
+ wide: Breit
portraitColor:
label: Farbe (Hochkant)
portraitActiveImage:
diff --git a/entry_types/scrolled/config/locales/new/hotspots.en.yml b/entry_types/scrolled/config/locales/new/hotspots.en.yml
index db1a4f835..5f758d802 100644
--- a/entry_types/scrolled/config/locales/new/hotspots.en.yml
+++ b/entry_types/scrolled/config/locales/new/hotspots.en.yml
@@ -31,6 +31,19 @@ en:
values:
indicator: At indicator
area: At area
+ tooltipMaxWidth:
+ label: Tooltip maximum width
+ values:
+ medium: Medium
+ narrow: Narrow
+ veryNarrow: Very Narrow
+ wide: Wide
+ tooltipTextAlign:
+ label: Text alignment in tooltip
+ values:
+ left: Left
+ center: Center
+ right: Right
color:
label: Color
activeImage:
@@ -51,6 +64,13 @@ en:
values:
indicator: At indicator
area: At area
+ portraitTooltipMaxWidth:
+ label: Tooltip maximum width (Portrait)
+ values:
+ medium: Medium
+ narrow: Narrow
+ veryNarrow: Very Narrow
+ wide: Wide
portraitColor:
label: Color (Portrait)
portraitActiveImage:
diff --git a/entry_types/scrolled/package/spec/contentElements/hotspots/Hotspots-spec.js b/entry_types/scrolled/package/spec/contentElements/hotspots/Hotspots-spec.js
index abdf2b479..b1e0b74ae 100644
--- a/entry_types/scrolled/package/spec/contentElements/hotspots/Hotspots-spec.js
+++ b/entry_types/scrolled/package/spec/contentElements/hotspots/Hotspots-spec.js
@@ -34,6 +34,7 @@ describe('Hotspots', () => {
this.callback = callback;
this.observe = observeResizeMock;
this.unobserve = function(element) {};
+ this.disconnect = function() {};
};
});
@@ -356,7 +357,7 @@ describe('Hotspots', () => {
const seed = {
imageFileUrlTemplates: {
large: 'large/:id_partition/image.webp',
- linkThumbnailLarge: 'linkThumbnailLarge/:id_partition/image.webp'
+ medium: 'medium/:id_partition/image.webp'
},
imageFiles: [{id: 1, permaId: 100}, {id: 2, permaId: 101}]
};
@@ -395,7 +396,7 @@ describe('Hotspots', () => {
expect(queryByText('Some link')).not.toBeNull();
expect(getByRole('link')).toHaveAttribute('href', 'https://example.com');
expect(getByRole('link')).toHaveAttribute('target', '_blank');
- expect(getByRole('img')).toHaveAttribute('src', 'linkThumbnailLarge/000/000/002/image.webp');
+ expect(getByRole('img')).toHaveAttribute('src', 'medium/000/000/002/image.webp');
});
it('does not render tooltip link if link text is blank', async () => {
@@ -424,14 +425,184 @@ describe('Hotspots', () => {
};
const user = userEvent.setup();
- const {container, queryByRole} = renderInContentElement(
+ const {container, queryByRole, simulateScrollPosition} = renderInContentElement(
, {seed}
);
+ simulateScrollPosition('near viewport');
await user.click(container.querySelector(`.${areaStyles.clip}`))
expect(queryByRole('link')).toBeNull();
});
+ it('does not apply min width to tooltip without link', async () => {
+ const seed = {
+ imageFileUrlTemplates: {large: ':id_partition/image.webp'},
+ imageFiles: [{id: 1, permaId: 100}]
+ };
+ const configuration = {
+ image: 100,
+ areas: [
+ {
+ id: 1,
+ indicatorPosition: [10, 20],
+ }
+ ],
+ tooltipTexts: {
+ 1: {
+ title: [{type: 'heading', children: [{text: 'Some title'}]}],
+ description: [{type: 'paragraph', children: [{text: 'Some description'}]}],
+ link: [{type: 'paragraph', children: [{text: ''}]}]
+ }
+ },
+ tooltipLinks: {
+ 1: {href: 'https://example.com', openInNewTab: true}
+ }
+ };
+
+ const user = userEvent.setup();
+ const {container, simulateScrollPosition} = renderInContentElement(
+ , {seed}
+ );
+ simulateScrollPosition('near viewport');
+ await user.click(container.querySelector(`.${areaStyles.clip}`))
+
+ expect(container.querySelector(`.${tooltipStyles.box}`)).not.toHaveClass(tooltipStyles.minWidth);
+ });
+
+ it('applies min width to tooltip with link', async () => {
+ const seed = {
+ imageFileUrlTemplates: {large: ':id_partition/image.webp'},
+ imageFiles: [{id: 1, permaId: 100}]
+ };
+ const configuration = {
+ image: 100,
+ areas: [
+ {
+ id: 1,
+ indicatorPosition: [10, 20],
+ }
+ ],
+ tooltipTexts: {
+ 1: {
+ title: [{type: 'heading', children: [{text: 'Some title'}]}],
+ description: [{type: 'paragraph', children: [{text: 'Some description'}]}],
+ link: [{type: 'paragraph', children: [{text: 'Some link'}]}]
+ }
+ },
+ tooltipLinks: {
+ 1: {href: 'https://example.com', openInNewTab: true}
+ }
+ };
+
+ const user = userEvent.setup();
+ const {container, simulateScrollPosition} = renderInContentElement(
+ , {seed}
+ );
+ simulateScrollPosition('near viewport');
+ await user.click(container.querySelector(`.${areaStyles.clip}`))
+
+ expect(container.querySelector(`.${tooltipStyles.box}`)).toHaveClass(tooltipStyles.minWidth);
+ });
+
+ it('applies max width to tooltip', async () => {
+ const seed = {
+ imageFileUrlTemplates: {large: ':id_partition/image.webp'},
+ imageFiles: [{id: 1, permaId: 100}]
+ };
+ const configuration = {
+ image: 100,
+ areas: [
+ {
+ id: 1,
+ indicatorPosition: [10, 20],
+ tooltipMaxWidth: 'narrow'
+ }
+ ],
+ tooltipTexts: {
+ 1: {
+ title: [{type: 'heading', children: [{text: 'Some title'}]}],
+ description: [{type: 'paragraph', children: [{text: 'Some description'}]}]
+ }
+ }
+ };
+
+ const user = userEvent.setup();
+ const {container, simulateScrollPosition} = renderInContentElement(
+ , {seed}
+ );
+ simulateScrollPosition('near viewport');
+ await user.click(container.querySelector(`.${areaStyles.clip}`))
+
+ expect(container.querySelector(`.${tooltipStyles.box}`)).toHaveClass(tooltipStyles['maxWidth-narrow']);
+ });
+
+ it('supports separate max width for portrait mode', async () => {
+ const seed = {
+ imageFileUrlTemplates: {large: ':id_partition/image.webp'},
+ imageFiles: [{id: 1, permaId: 100}]
+ };
+ const configuration = {
+ image: 100,
+ portraitImage: 100,
+ areas: [
+ {
+ id: 1,
+ indicatorPosition: [10, 20],
+ tooltipMaxWidth: 'narrow',
+ portraitTooltipMaxWidth: 'veryNarrow'
+ }
+ ],
+ tooltipTexts: {
+ 1: {
+ title: [{type: 'heading', children: [{text: 'Some title'}]}],
+ description: [{type: 'paragraph', children: [{text: 'Some description'}]}]
+ }
+ }
+ };
+
+ const user = userEvent.setup();
+ window.matchMedia.mockPortrait();
+ const {container, simulateScrollPosition} = renderInContentElement(
+ , {seed}
+ );
+ simulateScrollPosition('near viewport');
+ await user.click(container.querySelector(`.${areaStyles.clip}`))
+
+ expect(container.querySelector(`.${tooltipStyles.box}`)).toHaveClass(tooltipStyles['maxWidth-veryNarrow']);
+ });
+
+ it('supports setting tooltip text align', async () => {
+ const seed = {
+ imageFileUrlTemplates: {large: ':id_partition/image.webp'},
+ imageFiles: [{id: 1, permaId: 100}]
+ };
+ const configuration = {
+ image: 100,
+ areas: [
+ {
+ id: 1,
+ indicatorPosition: [10, 20],
+ tooltipTextAlign: 'center'
+ }
+ ],
+ tooltipTexts: {
+ 1: {
+ title: [{type: 'heading', children: [{text: 'Some title'}]}],
+ description: [{type: 'paragraph', children: [{text: 'Some description'}]}]
+ }
+ }
+ };
+
+ const user = userEvent.setup();
+ const {container, simulateScrollPosition} = renderInContentElement(
+ , {seed}
+ );
+ simulateScrollPosition('near viewport');
+ await user.click(container.querySelector(`.${areaStyles.clip}`))
+
+ expect(container.querySelector(`.${tooltipStyles.box}`)).toHaveClass(tooltipStyles['align-center']);
+ });
+
it('does not observe resize by default', () => {
const seed = {
imageFileUrlTemplates: {large: ':id_partition/image.webp'},
@@ -570,7 +741,7 @@ describe('Hotspots', () => {
image: 100,
areas: [
{
- indicatorPosition: [10, 20],
+ indicatorPosition: [15, 20],
outline: [[10, 20], [10, 30], [40, 30], [40, 15]],
tooltipReference: 'area'
}
@@ -584,9 +755,8 @@ describe('Hotspots', () => {
simulateScrollPosition('near viewport');
expect(container.querySelector(`.${tooltipStyles.reference}`)).toHaveStyle({
- left: '10px',
+ left: '15px',
top: '15px',
- width: '30px',
height: '15px'
});
});
@@ -618,9 +788,8 @@ describe('Hotspots', () => {
simulateScrollPosition('near viewport');
expect(container.querySelector(`.${tooltipStyles.reference}`)).toHaveStyle({
- left: '10px',
+ left: '20px',
top: '15px',
- width: '30px',
height: '15px'
});
});
@@ -654,7 +823,6 @@ describe('Hotspots', () => {
expect(container.querySelector(`.${tooltipStyles.reference}`)).toHaveStyle({
left: '10px',
top: '15px',
- width: '30px',
height: '15px'
});
});
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js
index 9972bc575..5e3a22140 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js
@@ -36,6 +36,7 @@ export function Tooltip({
panZoomEnabled, imageFile, containerRect, keepInViewport, floatingStrategy,
onMouseEnter, onMouseLeave, onClick, onDismiss,
}) {
+ const {t: translateWithEntryLocale} = useI18n();
const {t} = useI18n({locale: 'ui'});
const updateConfiguration = useContentElementConfigurationUpdate();
const {isEditable} = useContentElementEditorState();
@@ -55,6 +56,7 @@ export function Tooltip({
const referenceType = portraitMode ? area.portraitTooltipReference : area.tooltipReference;
const position = portraitMode ? area.portraitTooltipPosition : area.tooltipPosition;
+ const maxWidth = portraitMode ? area.portraitTooltipMaxWidth : area.tooltipMaxWidth;
const arrowRef = useRef();
const {refs, floatingStyles, context} = useFloating({
@@ -64,18 +66,14 @@ export function Tooltip({
placement: position === 'above' ? 'top' : 'bottom',
middleware: [
offset(referenceType === 'area' ? 7 : 20),
- shift({crossAxis: keepInViewport}),
+ shift({crossAxis: keepInViewport, padding: {left: 16, right: 16}}),
keepInViewport && flip(),
arrow({
- element: arrowRef
+ element: arrowRef,
+ padding: 5
})
],
- whileElementsMounted(referenceEl, floatingEl, update) {
- return autoUpdate(referenceEl, floatingEl, update, {
- elementResize: false,
- layoutShift: false,
- });
- }
+ whileElementsMounted: autoUpdate
});
const role = useRole(context, {role: 'label'});
@@ -107,7 +105,7 @@ export function Tooltip({
if (utils.isBlankEditableTextValue(tooltipTexts[area.id]?.link)) {
handleTextChange('link', [{
type: 'heading',
- children: [{text: t('pageflow_scrolled.public.more')}]
+ children: [{text: translateWithEntryLocale('pageflow_scrolled.public.more')}]
}]);
}
@@ -143,17 +141,20 @@ export function Tooltip({
{presentOrEditing('title') &&
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css
index 28e423acc..58e91218e 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css
@@ -24,11 +24,35 @@
background-color: #fff;
color: #000;
box-sizing: border-box;
- padding: 1rem;
+ padding: 0.75rem;
box-shadow: 0px 3px 3px -2px rgba(0,0,0,0.2), 0px 3px 4px 0px rgba(0,0,0,0.14), 0px 1px 8px 0px rgba(0,0,0,0.12);
border-radius: 5px;
- width: calc(100% - 2rem);
- max-width: 400px;
+ --max-width: 400px;
+ max-width: min(100% - 2rem, var(--max-width));
+}
+
+.maxWidth-wide {
+ --max-width: 600px;
+}
+
+.maxWidth-narrow {
+ --max-width: 300px;
+}
+
+.maxWidth-veryNarrow {
+ --max-width: 200px;
+}
+
+.align-center {
+ text-align: center;
+}
+
+.align-right {
+ text-align: right;
+}
+
+.minWidth {
+ min-width: 200px;
}
.box svg {
@@ -37,6 +61,7 @@
.box img {
width: 100%;
+ height: auto;
margin-bottom: 1rem;
}
@@ -47,7 +72,7 @@
.box > h3,
.box > div {
- margin-bottom: 0.5em;
+ margin-bottom: 0.5rem;
}
.box > :last-child {
@@ -60,10 +85,9 @@
gap: 0.5em;
border-radius: 5px;
text-decoration: none;
- padding: 0.75rem;
+ padding: 0.5rem;
background-color: var(--theme-widget-primary-color);
color: var(--theme-widget-on-primary-color);
- font-size: 18px;
margin-top: 1rem;
font-weight: bold;
}
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/editor/SidebarEditAreaView.js b/entry_types/scrolled/package/src/contentElements/hotspots/editor/SidebarEditAreaView.js
index 8042d471d..aa1e316bf 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/editor/SidebarEditAreaView.js
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/editor/SidebarEditAreaView.js
@@ -77,6 +77,10 @@ export const SidebarEditAreaView = Marionette.Layout.extend({
this.input('tooltipPosition', SelectInputView, {
values: ['below', 'above']
});
+ this.input('tooltipMaxWidth', SelectInputView, {
+ defaultValue: 'medium',
+ values: ['wide', 'medium', 'narrow', 'veryNarrow']
+ });
this.view(SeparatorView);
this.input('tooltipImage', FileInputView, {
collection: 'image_files',
@@ -87,6 +91,9 @@ export const SidebarEditAreaView = Marionette.Layout.extend({
},
positioning: false
});
+ this.input('tooltipTextAlign', SelectInputView, {
+ values: ['left', 'right', 'center']
+ });
});
if (portraitFile) {
@@ -124,6 +131,10 @@ export const SidebarEditAreaView = Marionette.Layout.extend({
this.input('portraitTooltipPosition', SelectInputView, {
values: ['below', 'above']
});
+ this.input('portraitTooltipMaxWidth', SelectInputView, {
+ defaultValue: 'medium',
+ values: ['wide', 'medium', 'narrow', 'veryNarrow']
+ });
});
}
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/editor/index.js b/entry_types/scrolled/package/src/contentElements/hotspots/editor/index.js
index e73cd7ec7..207e1a173 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/editor/index.js
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/editor/index.js
@@ -17,7 +17,7 @@ editor.registerSideBarRouting({
editor.contentElementTypes.register('hotspots', {
pictogram,
- category: 'links',
+ category: 'interactive',
featureName: 'hotspots_content_element',
supportedPositions: ['inline', 'sticky', 'standAlone', 'left', 'right', 'backdrop'],
supportedWidthRange: ['xxs', 'full'],
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/getTooltipReferencePosition.js b/entry_types/scrolled/package/src/contentElements/hotspots/getTooltipReferencePosition.js
index cb28633d0..247ebee15 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/getTooltipReferencePosition.js
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/getTooltipReferencePosition.js
@@ -6,38 +6,49 @@ export function getTooltipReferencePosition({
portraitMode,
panZoomEnabled, imageFile, containerRect
}) {
- const referenceType = portraitMode ? area.portraitTooltipReference : area.tooltipReference;
-
- const referencePositionInPercent =
- referenceType === 'area' ?
- getBoundingRect(portraitMode ? area.portraitOutline : area.outline) :
- getIndicatorRect(portraitMode ? area.portraitIndicatorPosition : area.indicatorPosition)
+ const referencePositionInPercent = getReferencePositionInPercent({area, portraitMode});
const transform =
panZoomEnabled ?
getPanZoomStepTransform({
- areaOutline: portraitMode ? area.portraitOutline : area.outline,
- areaZoom: (portraitMode ? area.portraitZoom : area.zoom) || 0,
- imageFileWidth: imageFile?.width,
- imageFileHeight: imageFile?.height,
- containerWidth: containerRect.width,
- containerHeight: containerRect.height
- }) :
- {x: 0, y: 0, scale: 1};
+ areaOutline: portraitMode ? area.portraitOutline : area.outline,
+ areaZoom: (portraitMode ? area.portraitZoom : area.zoom) || 0,
+ imageFileWidth: imageFile?.width,
+ imageFileHeight: imageFile?.height,
+ containerWidth: containerRect.width,
+ containerHeight: containerRect.height
+ }) :
+ {x: 0, y: 0, scale: 1};
return {
left: containerRect.width * transform.scale * referencePositionInPercent.left / 100 + transform.x,
top: containerRect.height * transform.scale * referencePositionInPercent.top / 100 + transform.y,
- width: containerRect.width * transform.scale * referencePositionInPercent.width / 100,
height: containerRect.height * transform.scale * referencePositionInPercent.height / 100
};
}
+function getReferencePositionInPercent({area, portraitMode}) {
+ const referenceType = portraitMode ? area.portraitTooltipReference : area.tooltipReference;
+ const indicatorRect = getIndicatorRect(portraitMode ? area.portraitIndicatorPosition : area.indicatorPosition);
+
+ if (referenceType === 'area') {
+ const boundingRect = getBoundingRect(portraitMode ? area.portraitOutline : area.outline);
+
+ return {
+ top: boundingRect.top,
+ height: boundingRect.height,
+ left: indicatorRect.left
+ }
+ }
+ else {
+ return indicatorRect;
+ }
+}
+
function getIndicatorRect(indicatorPosition = [50, 50]) {
return {
left: indicatorPosition[0],
top: indicatorPosition[1],
- width: 0,
height: 0
};
}
diff --git a/entry_types/scrolled/package/src/frontend/Text.module.css b/entry_types/scrolled/package/src/frontend/Text.module.css
index e2cf7cfe6..7a1c15ab2 100644
--- a/entry_types/scrolled/package/src/frontend/Text.module.css
+++ b/entry_types/scrolled/package/src/frontend/Text.module.css
@@ -1,3 +1,4 @@
+@value text-2xs: 16px;
@value text-xs: 18px;
@value text-s: 20px;
@value text-base: 22px;
@@ -188,20 +189,20 @@
.hotspotsTooltipTitle {
composes: typography-hotspotTooltipTitle from global;
- font-size: text-s;
+ font-size: text-xs;
line-height: 1.4;
font-weight: bold;
}
.hotspotsTooltipDescription {
composes: typography-hotspotTooltipDescription from global;
- font-size: text-s;
+ font-size: text-xs;
line-height: 1.4;
}
.hotspotsTooltipLink {
composes: typography-hotspotTooltipLink from global;
- font-size: text-xs;
+ font-size: text-2xs;
line-height: 1.4;
font-weight: bold;
}
diff --git a/package/spec/ui/views/inputs/SelectInputView-spec.js b/package/spec/ui/views/inputs/SelectInputView-spec.js
index 4f300bc9e..1f70cb535 100644
--- a/package/spec/ui/views/inputs/SelectInputView-spec.js
+++ b/package/spec/ui/views/inputs/SelectInputView-spec.js
@@ -23,6 +23,21 @@ describe('pageflow.SelectInputView', () => {
expect($('select', selectInputView.el).val()).toEqual('second');
});
+ it('saves value on change', () => {
+ var model = new Model();
+ var selectInputView = new SelectInputView({
+ model: model,
+ propertyName: 'value',
+ values: ['first', 'second']
+ });
+
+ selectInputView.render();
+ selectInputView.ui.select.val('second');
+ selectInputView.ui.select.trigger('change');
+
+ expect(model.get('value')).toEqual('second');
+ });
+
it('selects first option if value is not among values', () => {
var model = new Model({value: 'not there'});
var selectInputView = new SelectInputView({
@@ -240,6 +255,68 @@ describe('pageflow.SelectInputView', () => {
});
});
+ describe('with defaultValue', () => {
+ it('selects default value if property is not set', () => {
+ var model = new Model();
+ var selectInputView = new SelectInputView({
+ model: model,
+ propertyName: 'value',
+ values: ['small', 'medium', 'large'],
+ defaultValue: 'medium'
+ });
+
+ selectInputView.render();
+
+ expect($('select', selectInputView.el).val()).toEqual('medium');
+ });
+
+ it('selects current value if property is set', () => {
+ var model = new Model({value: 'small'});
+ var selectInputView = new SelectInputView({
+ model: model,
+ propertyName: 'value',
+ values: ['small', 'medium', 'large'],
+ defaultValue: 'medium'
+ });
+
+ selectInputView.render();
+
+ expect($('select', selectInputView.el).val()).toEqual('small');
+ });
+
+ it('does not save default value', () => {
+ var model = new Model({value: 'small'});
+ var selectInputView = new SelectInputView({
+ model: model,
+ propertyName: 'value',
+ values: ['small', 'medium', 'large'],
+ defaultValue: 'medium'
+ });
+
+ selectInputView.render();
+ selectInputView.ui.select.val('medium');
+ selectInputView.ui.select.trigger('change');
+
+ expect(model.has('value')).toEqual(false);
+ });
+
+ it('saves other values on change', () => {
+ var model = new Model({value: 'small'});
+ var selectInputView = new SelectInputView({
+ model: model,
+ propertyName: 'value',
+ values: ['small', 'medium', 'large'],
+ defaultValue: 'medium'
+ });
+
+ selectInputView.render();
+ selectInputView.ui.select.val('large');
+ selectInputView.ui.select.trigger('change');
+
+ expect(model.get('value')).toEqual('large');
+ });
+ });
+
function optionTexts(view) {
view.render();
diff --git a/package/src/ui/views/inputs/SelectInputView.js b/package/src/ui/views/inputs/SelectInputView.js
index b26dd3575..e7cdcf021 100644
--- a/package/src/ui/views/inputs/SelectInputView.js
+++ b/package/src/ui/views/inputs/SelectInputView.js
@@ -17,6 +17,9 @@ import template from '../../templates/inputs/selectInput.jst';
* @param {string[]} [options.values]
* List of possible values to persist in the attribute.
*
+ * @param {number} [options.defaultValue]
+ * Default value to display if property is not set.
+ *
* @param {string[]} [options.texts]
* List of display texts for drop down items.
*
@@ -226,7 +229,14 @@ export const SelectInputView = Marionette.ItemView.extend({
},
save: function() {
- this.model.set(this.options.propertyName, this.ui.select.val());
+ const value = this.ui.select.val();
+
+ if ('defaultValue' in this.options && value === this.options.defaultValue) {
+ this.model.unset(this.options.propertyName);
+ }
+ else {
+ this.model.set(this.options.propertyName, value);
+ }
},
load: function() {
@@ -236,7 +246,9 @@ export const SelectInputView = Marionette.ItemView.extend({
if (this.model.has(this.options.propertyName) &&
this.ui.select.find('option[value="' + value +'"]:not([disabled])').length) {
this.ui.select.val(value);
-
+ }
+ else if ('defaultValue' in this.options) {
+ this.ui.select.val(this.options.defaultValue);
}
else {
this.ui.select.val(this.ui.select.find('option:not([disabled]):first').val());
diff --git a/package/src/ui/views/inputs/SliderInputView.js b/package/src/ui/views/inputs/SliderInputView.js
index 50b161950..21ca0c2e8 100644
--- a/package/src/ui/views/inputs/SliderInputView.js
+++ b/package/src/ui/views/inputs/SliderInputView.js
@@ -12,7 +12,7 @@ import template from '../../templates/inputs/sliderInput.jst';
* @param {Object} [options]
*
* @param {number} [options.defaultValue]
- * Defaults value to display if property is not set.
+ * Default value to display if property is not set.
*
* @param {number} [options.minValue=0]
* Value when dragging slider to the very left.