Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
[style]="{ left: model.getPercent(item.value) + '%' }"
(pointerup)="model.handleLabelPointerUp($any($event), item.value)">
<div [class]="model.cssClasses.labelTick"></div>
<div [class]="model.cssClasses.labelText" [model]="item.locText" sv-ng-string></div>
<div [class]="model.cssClasses.labelTextContainer">
<div *ngIf="!item.showValue" [class]="model.cssClasses.labelText" [model]="item.locText" sv-ng-string></div>
<div *ngIf="item.showValue" [class]="model.cssClasses.labelText">{{ item.value }}</div>
<div *ngIf="item.showValue" [class]="model.cssClasses.labelTextSecondaryMode" [model]="item.locText" sv-ng-string></div>
</div>
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Input } from "@angular/core";
import { ItemValue, QuestionSliderModel } from "survey-core";
import { QuestionSliderModel, SliderLabelItemValue } from "survey-core";
import { BaseAngular } from "../../base-angular";
import { AngularComponentFactory } from "../../component-factory";

Expand All @@ -10,7 +10,7 @@ import { AngularComponentFactory } from "../../component-factory";

export class SliderLabelItemComponent extends BaseAngular {
@Input() model!: QuestionSliderModel;
@Input() item!: ItemValue;
@Input() item!: SliderLabelItemValue;

// onClick(event: any): void {
// this.model.setValueFromClick(event.target.value);
Expand Down
2 changes: 1 addition & 1 deletion packages/survey-core/entries/chunks/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export { QuestionFileModelBase, QuestionFileModel, QuestionFilePage } from "../.
export { QuestionHtmlModel } from "../../src/question_html";
export { QuestionRadiogroupModel } from "../../src/question_radiogroup";
export { QuestionRatingModel, RenderedRatingItem } from "../../src/question_rating";
export { QuestionSliderModel } from "../../src/question_slider";
export { QuestionSliderModel, SliderLabelItemValue } from "../../src/question_slider";
export { QuestionExpressionModel } from "../../src/question_expression";
export { QuestionTextBase, CharacterCounter } from "../../src/question_textbase";
export { QuestionTextModel } from "../../src/question_text";
Expand Down
48 changes: 37 additions & 11 deletions packages/survey-core/src/default-theme/blocks/sd-slider.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@
// }
}

.sd-slider--tooltips-always-mode {
margin-top: var(--lbr-slider-margin-top-tooltip, calcSize(5));
}

.sd-slider-container {
position: relative;
min-height: var(--sjs-postcss-fix-slider-thumb-height);
Expand Down Expand Up @@ -265,6 +261,7 @@
cursor: pointer;
color: $foreground;
position: absolute;
top: 0;
width: var(--sjs-postcss-fix-slider-thumb-width);
display: flex;
flex-direction: column;
Expand All @@ -273,12 +270,12 @@
margin-left: calc(var(--sjs-postcss-fix-slider-thumb-width) / -2);
}

.sd-slider__label--long:first-child {
align-items: flex-start;
.sd-slider__label--long:first-child .sd-slider__label-text-container {
align-self: flex-start;
}

.sd-slider__label--long:last-child {
align-items: flex-end;
.sd-slider__label--long:last-child .sd-slider__label-text-container {
align-self: flex-end;
}

.sd-slider__label-tick {
Expand All @@ -300,6 +297,10 @@
line-height: var(--lbr-font-default-line-height, calcSize(3));
}

.sd-slider__label-text--secondary {
color: var(--lbr-slider-label-text-color-secondary, $font-questiondescription-color);
}

input[type="range"].sd-slider__input {
position: absolute;
pointer-events: none;
Expand Down Expand Up @@ -491,6 +492,10 @@ input[type="range"][name="range-input"].sd-slider__input::-moz-range-thumb {
.sd-slider__label-tick {
background: var(--lbr-slider-label-tick-color, $border-light);
}

.sd-slider__label-text--secondary {
color: var(--lbr-slider-label-text-color, $font-editorfont-color);
}
}

.sd-question--preview {
Expand All @@ -501,7 +506,7 @@ input[type="range"][name="range-input"].sd-slider__input::-moz-range-thumb {
}
}

&.sd-slider--negative-scale {
&.sd-slider--negative-scale-mode {
}
}

Expand Down Expand Up @@ -563,7 +568,7 @@ input[type="range"][name="range-input"].sd-slider__input::-moz-range-thumb {
}
}

.sd-slider--negative-scale {
.sd-slider--negative-scale-mode {
.sd-slider__inverse-track--left {
&::before {
background: var(--lbr-slider-path-color-preview, $border-light);
Expand All @@ -574,6 +579,10 @@ input[type="range"][name="range-input"].sd-slider__input::-moz-range-thumb {
.sd-slider__label-tick {
background: var(--lbr-slider-label-tick-color-preview, $foreground);
}

.sd-slider__label-text--secondary {
color: var(--lbr-slider-label-text-color, $font-editorfont-color);
}
}

.sd-question--error {
Expand Down Expand Up @@ -644,7 +653,7 @@ input[type="range"][name="range-input"].sd-slider__input::-moz-range-thumb {
}
}

.sd-slider--negative-scale {
.sd-slider--negative-scale-mode {
.sd-slider__range-track {
&::before {
display: none;
Expand All @@ -669,6 +678,23 @@ input[type="range"][name="range-input"].sd-slider__input::-moz-range-thumb {
}
}

.sd-slider--tooltips-always-mode {
margin-top: var(--lbr-slider-margin-top-tooltip, calcSize(5));
}

.sd-slider--labels-show-value-text-mode {
margin-bottom: calcSize(3);

.sd-slider__label--long:first-child .sd-slider__label-text:first-child {
text-align: start;
margin-left: 11px;
}

.sd-slider__label--long:last-child .sd-slider__label-text:first-child {
text-align: end;
}
}

[dir="rtl"],
[style*="direction:rtl"],
[style*="direction: rtl"] {
Expand Down
5 changes: 4 additions & 1 deletion packages/survey-core/src/defaultCss/defaultCss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -683,10 +683,11 @@ export var defaultCss = {
slider: {
root: "sd-slider",
rootSingleMode: "sd-slider--single",
rootNegativeScaleMode: "sd-slider--negative-scale",
rootNegativeScaleMode: "sd-slider--negative-scale-mode",
rootDesignMode: "sd-slider--design-mode",
rootAnimatedThumbMode: "sd-slider--animated-thumb-mode",
rootTooltipsAlwaysMode: "sd-slider--tooltips-always-mode",
rootLabelsShowValueTextMode: "sd-slider--labels-show-value-text-mode",
visualContainer: "sd-slider-container",
visualContainerSlider: "sd-slider-container__slider",
rangeTrack: "sd-slider__track sd-slider__range-track",
Expand All @@ -706,7 +707,9 @@ export var defaultCss = {
label: "sd-slider__label",
labelLongMod: "sd-slider__label--long",
labelTick: "sd-slider__label-tick",
labelTextContainer: "sd-slider__label-text-container",
labelText: "sd-slider__label-text",
labelTextSecondaryMode: "sd-slider__label-text sd-slider__label-text--secondary",
clearButton: "",
},
comment: {
Expand Down
27 changes: 21 additions & 6 deletions packages/survey-core/src/question_slider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ export class SliderLabelItemValue extends ItemValue {
}
return this.value || 0;
}
public get showValue(): boolean {
return this.getPropertyValue("showValue", false);
}
public set showValue(val: boolean) {
this.setPropertyValue("showValue", val);
}
}

/**
Expand Down Expand Up @@ -193,7 +199,10 @@ export class QuestionSliderModel extends Question implements ISliderLabelItemOwn
* - `text`: `string`\
* The label text to display.
*
* Numbers and objects can be combined in the same array. For instance, the following slider configuration specifies textual labels for extreme scale points and adds numeric labels between them.
* - `showValue`: `boolean`\
* Specifies whether to display the numeric value alongside the label text. Default value: `false`.
*
* Numbers and objects can be combined in the same array. For instance, the following slider configuration adds textual labels for the minimum and maximum scale values and numeric labels for intermediate points. The extreme labels also display their corresponding values.
*
* ```js
* const surveyJson = {
Expand All @@ -202,12 +211,12 @@ export class QuestionSliderModel extends Question implements ISliderLabelItemOwn
* "type": "slider",
* // ...
* "customLabels": [
* { value: 0, text: "Lowest" },
* { "value": 0, "text": "Lowest", "showValue": true },
* 20,
* 40
* 60
* 80,
* { value: 100, text: "Highest" },
* { "value": 100, "text": "Highest", "showValue": true }
* ]
* }
* ]
Expand All @@ -219,10 +228,10 @@ export class QuestionSliderModel extends Question implements ISliderLabelItemOwn
* @see labelCount
* @see labelFormat
*/
public get customLabels(): ItemValue[] {
public get customLabels(): SliderLabelItemValue[] {
return this.getPropertyValue("customLabels");
}
public set customLabels(val: ItemValue[]) {
public set customLabels(val: SliderLabelItemValue[]) {
this.setPropertyValue("customLabels", val);
}
@property({ defaultValue: true }) allowDragRange: boolean;
Expand Down Expand Up @@ -277,6 +286,7 @@ export class QuestionSliderModel extends Question implements ISliderLabelItemOwn
.append(this.cssClasses.rootDesignMode, !!this.isDesignMode)
.append(this.cssClasses.rootAnimatedThumbMode, !!this.animatedThumb)
.append(this.cssClasses.rootTooltipsAlwaysMode, this.tooltipVisibility === "always")
.append(this.cssClasses.rootLabelsShowValueTextMode, this.isLabelsShowValueText)
.toString();
}

Expand Down Expand Up @@ -889,6 +899,10 @@ export class QuestionSliderModel extends Question implements ISliderLabelItemOwn
private isAllowToChange():boolean {
return !this.isReadOnly && !this.isDisabledAttr && !this.isPreviewStyle && !this.isDisabledStyle;
}

private get isLabelsShowValueText(): boolean {
return !!this.customLabels.find(l => l.showValue);
}
}

function getCorrectMinMax(min: any, max: any, isMax: boolean, step: number): any {
Expand All @@ -902,7 +916,8 @@ Serializer.addClass(
[
{ name: "!value:number" },
{ name: "visibleIf", visible: false },
{ name: "enableIf", visible: false }
{ name: "enableIf", visible: false },
{ name: "showValue:boolean", locationInTable: "detail", default: false }
],
(value: any) => new SliderLabelItemValue(value),
"itemvalue"
Expand Down
3 changes: 1 addition & 2 deletions packages/survey-core/tests/question_slider_tests.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { ItemValue } from "../src/itemvalue";
import { QuestionSliderModel, SliderLabelItemValue } from "../src/question_slider";
import { SurveyModel } from "../src/survey";

Expand Down Expand Up @@ -804,7 +803,7 @@ QUnit.test("check if customLabels produces correct renderedLabels", (assert) =>
let q1 = new QuestionSliderModel("q1");
q1.max = 1000;
q1.autoGenerate = false;
q1.customLabels = [new ItemValue(500, "middle")];
q1.customLabels = [new SliderLabelItemValue(500, "middle")];
assert.deepEqual(q1.renderedLabels[0].text, "middle", "text is correct");
assert.deepEqual(q1.renderedLabels[0].value, 500, "value is correct");
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,24 @@ export class SliderLabelItem extends SurveyElementBase<any, any> {
protected renderElement(): React.JSX.Element {
const { cssClasses, handleLabelPointerUp, getLabelCss, getPercent } = this.question;
const { value, locText } = this.item;
let labelText = null;
let labelTextSecondary = null;
if (this.item.showValue) {
labelText = <div className={cssClasses.labelText}>{this.item.value}</div>;
labelTextSecondary = <div className={cssClasses.labelTextSecondaryMode}>
{this.renderLocString(locText)}
</div>;
} else {
labelText = <div className={cssClasses.labelText}>
{this.renderLocString(locText)}
</div>;
}
return <div key={this.item.id} className={getLabelCss(locText)}
style={{ left: getPercent(value) + "%" }} onPointerUp={ (e)=>{ handleLabelPointerUp(e.nativeEvent, value); } }>
<div className={cssClasses.labelTick}></div>
<div className={cssClasses.labelText}>
{this.renderLocString(locText)}
<div className={cssClasses.labelTextContainer}>
{labelText}
{labelTextSecondary}
</div>
</div>;
}
Expand Down
21 changes: 16 additions & 5 deletions packages/survey-vue3-ui/src/components/slider/SliderLabelItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@
<div :class="question.getLabelCss(item.locText)"
:style="{ left: question.getPercent(item.value) + '%' }" @pointerup="(e)=>{question.handleLabelPointerUp(e, item.value )}">
<div :class="question.cssClasses.labelTick"></div>
<div :class="question.cssClasses.labelText">
<SvComponent
:is="'survey-string'"
:locString="item.locText"
/>
<div :class="question.cssClasses.labelTextContainer">
<div :class="question.cssClasses.labelText" v-if="!item.showValue">
<SvComponent
:is="'survey-string'"
:locString="item.locText"
/>
</div>
<div :class="question.cssClasses.labelText" v-if="item.showValue">
{{item.value}}
</div>
<div :class="question.cssClasses.labelTextSecondaryMode" v-if="item.showValue">
<SvComponent
:is="'survey-string'"
:locString="item.locText"
/>
</div>
</div>
</div>
</template>
Expand Down
4 changes: 2 additions & 2 deletions packages/survey-vue3-ui/src/components/slider/slider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { QuestionSliderModel, ItemValue } from "survey-core";
import type { QuestionSliderModel, SliderLabelItemValue } from "survey-core";

export interface ISliderItemProps {
question: QuestionSliderModel;
item: ItemValue;
item: SliderLabelItemValue;
}
40 changes: 40 additions & 0 deletions screenshots/slider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,5 +220,45 @@ frameworks.forEach(framework => {
await compareScreenshot(page, ".sd-question", "slider-single-tooltips-always.png");
});

test("Slider: Custom Labels", async ({ page }) => {
const json = {
"elements": [
{
"type": "slider",
"name": "q1",
"customLabels": [
0,
20,
40,
60,
80,
100,
]
}
]
};
const question = new Question(page, "q1");
await page.setViewportSize({ width: 1920, height: 1080 });
await initSurvey(page, framework, json);

await compareScreenshot(page, ".sd-question", "slider-custom-labels.png");

await question.setPropertyValue("customLabels", [
{ value: 0, text: "Lowest", showValue: true },
20,
40,
{ value: 60, text: "Middle" },
80,
{ value: 100, text: " Highest", showValue: true },
]);
await compareScreenshot(page, ".sd-question", "slider-custom-labels-secondary.png");

await question.setPropertyValue("readOnly", true);
await compareScreenshot(page, ".sd-question", "slider-custom-labels-secondary--read-only.png");

await new Survey(page).showPreview();
await compareScreenshot(page, ".sd-question", "slider-custom-labels-secondary--preview.png");
});

});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading