Skip to content

Commit

Permalink
Merge pull request #8397 from surveyjs/feature/layout
Browse files Browse the repository at this point in the history
Set the same title width option for questions when titleLocation is left
  • Loading branch information
andrewtelnov authored Jun 17, 2024
2 parents 8d5e0b0 + ecd042a commit 39d819a
Show file tree
Hide file tree
Showing 13 changed files with 109 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export class ElementHeaderComponent {
@HostBinding("class") get rootClass(): string {
return this.element.cssHeader;
}
@HostBinding("style.width") get width(): string {
return this.element.titleWidth;
}
@HostListener("click", ["$event"]) click(e: MouseEvent): void {
if (this.element.clickTitleFunction !== undefined) {
this.element.clickTitleFunction(e);
Expand Down
9 changes: 8 additions & 1 deletion packages/survey-vue3-ui/src/ElementHeader.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div :class="element.cssHeader" @click="clickTitleFunction">
<div :class="element.cssHeader" @click="clickTitleFunction" :style="getStyle()">
<survey-element-title :element="element" :css="css" />
<div v-if="element.hasDescriptionUnderTitle" v-show="element.hasDescription" :class="element.cssDescription"
:id="element.ariaDescriptionId">
Expand All @@ -18,4 +18,11 @@ const clickTitleFunction = (e: any) => {
props.element.clickTitleFunction(e);
}
};
const getStyle = () => {
const headerStyle: any = { width: undefined };
if("titleWidth" in props.element) {
headerStyle.width = props.element.titleWidth;
}
return headerStyle;
};
</script>
1 change: 1 addition & 0 deletions src/base-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ export interface IParentElement {
export interface IPanel extends ISurveyElement, IParentElement {
getChildrenLayoutType(): string;
getQuestionTitleLocation(): string;
getQuestionTitleWidth(): string;
getQuestionStartIndex(): string;
getQuestionErrorLocation(): string;
parent: IPanel;
Expand Down
2 changes: 1 addition & 1 deletion src/knockout/templates/questiontitle.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script type="text/html" id="survey-question-title">
<div data-bind="css: question.cssHeader, click: function(m, e) { if(question.clickTitleFunction) return question.clickTitleFunction(e); }">
<div data-bind="css: question.cssHeader, style: { width: $data.titleWidth }, click: function(m, e) { if(question.clickTitleFunction) return question.clickTitleFunction(e); }">
<!-- ko component: { name: 'survey-element-title', params: { element: $data } } --><!-- /ko -->
<!-- ko if: $data.hasDescriptionUnderTitle -->
<div data-bind="css: $data.cssDescription, visible: $data.hasDescription, attr: {'id': $data.ariaDescriptionId}">
Expand Down
10 changes: 10 additions & 0 deletions src/panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,10 @@ export class PanelModelBase extends SurveyElement<Question>
if (this.parent) return this.parent.getQuestionTitleLocation();
return this.survey ? this.survey.questionTitleLocation : "top";
}
@property() questionTitleWidth: string;
getQuestionTitleWidth(): string {
return this.questionTitleWidth || this.parent && this.parent.getQuestionTitleWidth();
}
protected getStartIndex(): string {
if (!!this.parent) return this.parent.getQuestionStartIndex();
if (!!this.survey) return this.survey.questionStartIndex;
Expand Down Expand Up @@ -2134,6 +2138,12 @@ Serializer.addClass(
"visibleIf:condition",
"enableIf:condition",
"requiredIf:condition",
{
name: "questionTitleWidth",
visibleIf: function (obj: any) {
return !!obj && obj["getQuestionTitleLocation"]() === "left";
}
},
{
name: "questionTitleLocation",
default: "default",
Expand Down
6 changes: 6 additions & 0 deletions src/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,12 @@ export class Question extends SurveyElement<Question>
this.clearValueIfInvisible();
}
}
public get titleWidth(): string {
if (this.getTitleLocation() === "left") {
if (!!this.parent) return this.parent.getQuestionTitleWidth();
}
return undefined;
}
/**
* Returns title location calculated based on the question's `titleLocation` property and the `questionTitleLocation` property of the question's containers (survey, page, or panel).
* @see titleLocation
Expand Down
3 changes: 3 additions & 0 deletions src/question_custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,9 @@ export abstract class QuestionCustomModelBase extends Question
getQuestionTitleLocation(): string {
return "left";
}
getQuestionTitleWidth(): string {
return undefined;
}
getQuestionStartIndex(): string {
return this.getStartIndex();
}
Expand Down
3 changes: 3 additions & 0 deletions src/question_multipletext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,9 @@ export class QuestionMultipleTextModel extends Question
getQuestionTitleLocation(): string {
return "left";
}
getQuestionTitleWidth(): string {
return undefined;
}
getQuestionStartIndex(): string {
return this.getStartIndex();
}
Expand Down
7 changes: 6 additions & 1 deletion src/react/element-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ export class SurveyElementHeader extends React.Component<any, any> {

const additionalTitleToolbarElement = element.hasAdditionalTitleToolbar ? <SurveyActionBar model={element.additionalTitleToolbar}></SurveyActionBar> : null;

const headerStyle: any = { width: undefined };
if(element instanceof Question) {
headerStyle.width = element.titleWidth;
}

return (
<div className={element.cssHeader} onClick={(e) => element.clickTitleFunction && element.clickTitleFunction(e.nativeEvent)}>
<div className={element.cssHeader} onClick={(e) => element.clickTitleFunction && element.clickTitleFunction(e.nativeEvent)} style={headerStyle}>
{title}
{description}
{additionalTitleToolbarElement}
Expand Down
10 changes: 9 additions & 1 deletion src/vue/elementheader.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div :class="element.cssHeader" @click="clickTitleFunction">
<div :class="element.cssHeader" @click="clickTitleFunction" :style="titleStyle">
<survey-element-title :element="element" :css="css" />
<div v-if="element.hasDescriptionUnderTitle" v-show="element.hasDescription" :class="element.cssDescription"
:id="element.ariaDescriptionId">
Expand All @@ -24,6 +24,14 @@ export class ElementHeader extends Vue {
(<any>this.element).clickTitleFunction(e);
}
}
get titleStyle() {
const headerStyle: any = { width: undefined };
if("titleWidth" in this.element) {
headerStyle.width = this.element.titleWidth;
}
return headerStyle;
}
}
Vue.component("survey-element-header", ElementHeader);
export default ElementHeader;
Expand Down
23 changes: 23 additions & 0 deletions tests/markup/etalon_page_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,29 @@ registerMarkupTest(
snapshot: "page-swnl-title-v2",
});

registerMarkupTest({
name: "Test Page - start with new line Title",
json: {
"pages": [
{
"name": "page1",
"questionTitleLocation": "left",
"questionTitleWidth": "500px",
"elements": [
{
"type": "text",
"name": "name",
"title": "Employee name:",
}
]
}]
},
before: () => StylesManager.applyTheme("defaultV2"),
after: () => StylesManager.applyTheme("default"),
event: "onAfterRenderPage",
snapshot: "page-questionTitleWidth",
});

registerMarkupTest(
{
name: "Test Panel - Panel/Questions titles and descriptions",
Expand Down
14 changes: 14 additions & 0 deletions tests/markup/snapshots/page-questionTitleWidth.snap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div style="flex:1 1 100%; max-width:100%; min-width:min(100%, 300px);">
<div class="sd-element sd-element--with-frame sd-question sd-question--left sd-row__question sd-row__question--small" data-name="name" id="testid0">
<div class="sd-element__header sd-question__header sd-question__header--location--left" style="width:500px;">
<h5 class="sd-element__title sd-question__title sd-title" id="testid0_ariaTitle">
<span aria-hidden="true" class="sd-element__num" style="position:static;">1.</span>
<span>&nbsp;</span>
<span class="sv-string-viewer sv-string-viewer--multiline">Employee name:</span>
</h5>
</div>
<div class="sd-question__content sd-question__content--left sd-text__content" role="presentation">
<input aria-describedby="testid0_ariaDescription" aria-invalid="false" aria-labelledby="testid0_ariaTitle" aria-required="false" class="sd-input sd-text" id="testid0i" placeholder="" type="text">
</div>
</div>
</div>
22 changes: 22 additions & 0 deletions tests/surveytests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6898,6 +6898,28 @@ QUnit.test("Define questionTitleLocation on Panel/Page level", function (
assert.equal(q.getTitleLocation(), "top", "get from survey again");
});

QUnit.test("Define questionTitleWidth on Panel/Page level", function (assert) {
const survey = new SurveyModel();
const page = survey.addNewPage("page");
const panel = page.addNewPanel("panel");
const panel2 = panel.addNewPanel("panel2");
const q = <Question>panel2.addNewQuestion("text");
page.questionTitleLocation = "left";

assert.equal(q.titleWidth, undefined, "init");
page.questionTitleWidth = "500px";
assert.equal(q.titleWidth, "500px", "get from page");

panel.questionTitleWidth = "50%";
assert.equal(q.titleWidth, "50%", "get from panel");

panel2.questionTitleWidth = "200px";
assert.equal(q.titleWidth, "200px", "get from panel2");

q.titleLocation = "top";
assert.equal(q.titleWidth, undefined, "titleWidth available if titleLocation is left");
});

QUnit.test("Question property.page getChoices", function (assert) {
var property = Serializer.findProperty("questionbase", "page");
assert.ok(property, "page property is here");
Expand Down

0 comments on commit 39d819a

Please sign in to comment.