From b7175c592be1aebec3b1bce53170397498cdac96 Mon Sep 17 00:00:00 2001 From: Andrew Telnov Date: Mon, 29 Jan 2024 09:58:37 +0200 Subject: [PATCH] Add properties into selectbase #7754 --- src/localization/english.ts | 2 + src/question_baseselect.ts | 84 ++++++++++++++++++++++++---- src/question_checkbox.ts | 2 +- src/settings.ts | 2 + tests/paneltests.ts | 4 +- tests/questionDropdownTests.ts | 2 +- tests/question_baseselecttests.ts | 18 +++--- tests/question_matrixdynamictests.ts | 2 +- tests/question_tagbox_tests.ts | 2 +- tests/surveyquestiontests.ts | 44 +++++++-------- 10 files changed, 114 insertions(+), 48 deletions(-) diff --git a/src/localization/english.ts b/src/localization/english.ts index bdb2f8a8fb..2293a554a9 100644 --- a/src/localization/english.ts +++ b/src/localization/english.ts @@ -10,6 +10,8 @@ export var englishStrings = { startSurveyText: "Start", otherItemText: "Other (describe)", noneItemText: "None", + refuseItemText: "Refuse to answer", + donotKnowItemText: "Do not know", selectAllItemText: "Select All", progressText: "Page {0} of {1}", indexText: "{0} of {1}", diff --git a/src/question_baseselect.ts b/src/question_baseselect.ts index f36d2cac6c..f3ef988912 100644 --- a/src/question_baseselect.ts +++ b/src/question_baseselect.ts @@ -29,7 +29,9 @@ export class QuestionSelectBase extends Question { private cachedValueForUrlRequests: any; private isChoicesLoaded: boolean; private enableOnLoadingChoices: boolean; - private noneItemValue: ItemValue = new ItemValue(settings.noneItemValue); + private noneItemValue: ItemValue; + private refuseItemValue: ItemValue; + private donotKnowItemValue: ItemValue; private newItemValue: ItemValue; private canShowOptionItemCallback: (item: ItemValue) => boolean; private waitingGetChoiceDisplayValueResponse: boolean; @@ -42,10 +44,9 @@ export class QuestionSelectBase extends Question { constructor(name: string) { super(name); - var noneItemText = this.createLocalizableString("noneText", this.noneItemValue, true, "noneItemText"); - this.noneItemValue.locOwner = this; - this.noneItemValue.setLocText(noneItemText); - + this.noneItemValue = this.createDefaultItem(settings.noneItemValue, "noneText", "noneItemText"); + this.refuseItemValue = this.createDefaultItem(settings.refuseItemValue, "refuseText", "refuseItemText"); + this.donotKnowItemValue = this.createDefaultItem(settings.donotKnowItemValue, "donotKnowText", "donotKnowItemText"); this.createItemValues("choices"); this.registerPropertyChangedHandlers(["choices"], () => { if (!this.filterItems()) { @@ -183,7 +184,7 @@ export class QuestionSelectBase extends Question { return this.hasOther && this.getHasOther(this.renderedValue); } public get isNoneSelected(): boolean { - return this.hasNone && this.getIsItemValue(this.renderedValue, this.noneItem); + return this.showNoneItem && this.getIsItemValue(this.renderedValue, this.noneItem); } /** * Specifies whether to display the "None" choice item. @@ -225,6 +226,49 @@ export class QuestionSelectBase extends Question { get locNoneText(): LocalizableString { return this.getLocalizableString("noneText"); } + public get showRefuseItem(): boolean { + return this.getPropertyValue("showRefuseItem"); + } + public set showRefuseItem(val: boolean) { + this.setPropertyValue("showRefuseItem", val); + } + public get refuseItem(): ItemValue { + return this.refuseItemValue; + } + public get refuseText(): string { + return this.getLocalizableStringText("refuseText"); + } + public set refuseText(val: string) { + this.setLocalizableStringText("refuseText", val); + } + get locRefuseText(): LocalizableString { + return this.getLocalizableString("refuseText"); + } + public get showDonotKnowItem(): boolean { + return this.getPropertyValue("showDonotKnowItem"); + } + public set showDonotKnowItem(val: boolean) { + this.setPropertyValue("showDonotKnowItem", val); + } + public get donotKnowItem(): ItemValue { + return this.donotKnowItemValue; + } + public get donotKnowText(): string { + return this.getLocalizableStringText("donotKnowText"); + } + public set donotKnowText(val: string) { + this.setLocalizableStringText("donotKnowText", val); + } + get locDonotKnowText(): LocalizableString { + return this.getLocalizableString("donotKnowText"); + } + private createDefaultItem(defaultValue: any, name: string, locName: string): ItemValue { + const item = new ItemValue(defaultValue); + const locStr = this.createLocalizableString(name, item, true, locName); + item.locOwner = this; + item.setLocText(locStr); + return item; + } /** * A Boolean expression that is evaluated against each choice item. If the expression evaluates to `false`, the choice item becomes hidden. * @@ -636,7 +680,7 @@ export class QuestionSelectBase extends Question { ): boolean { if (!checkEmptyValue && this.isValueEmpty(val)) return false; if (includeOther && val == this.otherItem.value) return false; - if (this.hasNone && val == this.noneItem.value) return false; + if (this.showNoneItem && val == this.noneItem.value) return false; var choices = isFilteredChoices ? this.getFilteredChoices() : this.activeChoices; @@ -904,7 +948,7 @@ export class QuestionSelectBase extends Question { protected canUseFilteredChoices(): boolean { return ( !this.isAddDefaultItems && - !this.hasNone && + !this.showNoneItem && !this.hasOther && this.choicesOrder == "none" ); @@ -953,7 +997,7 @@ export class QuestionSelectBase extends Question { } protected addNonChoicesItems(dict: Array<{ index: number, item: ItemValue }>, isAddAll: boolean): void { if ( - this.supportNone() && this.canShowOptionItem(this.noneItem, isAddAll, this.hasNone) + this.supportNone() && this.canShowOptionItem(this.noneItem, isAddAll, this.showNoneItem) ) { this.addNonChoiceItem(dict, this.noneItem, settings.specialChoicesOrder.noneItem); } @@ -976,7 +1020,7 @@ export class QuestionSelectBase extends Question { } public isItemInList(item: ItemValue): boolean { if (item === this.otherItem) return this.hasOther; - if (item === this.noneItem) return this.hasNone; + if (item === this.noneItem) return this.showNoneItem; if (item === this.newItemValue) return false; return true; } @@ -1920,6 +1964,8 @@ Serializer.addClass( { name: "separateSpecialChoices:boolean", visible: false }, { name: "showOtherItem:boolean", alternativeName: "hasOther" }, { name: "showNoneItem:boolean", alternativeName: "hasNone" }, + { name: "showRefuseItem:boolean", visible: false }, + { name: "showDonotKnowItem:boolean", visible: false }, { name: "otherPlaceholder", alternativeName: "otherPlaceHolder", @@ -1934,7 +1980,23 @@ Serializer.addClass( serializationProperty: "locNoneText", dependsOn: "showNoneItem", visibleIf: function (obj: any) { - return obj.hasNone; + return obj.showNoneItem; + }, + }, + { + name: "refuseText", + serializationProperty: "locRefuseText", + dependsOn: "showRefuseItem", + visibleIf: function (obj: any) { + return obj.showRefuseItem; + }, + }, + { + name: "donotKnowText", + serializationProperty: "locDonotKnowText", + dependsOn: "showDonotKnowItem", + visibleIf: function (obj: any) { + return obj.showDonotKnowItem; }, }, { diff --git a/src/question_checkbox.ts b/src/question_checkbox.ts index 1a96025d57..693f21de38 100644 --- a/src/question_checkbox.ts +++ b/src/question_checkbox.ts @@ -374,7 +374,7 @@ export class QuestionCheckboxModel extends QuestionCheckboxBase { if (!newValue) newValue = []; if (!value) value = []; if (this.isTwoValueEquals(value, newValue)) return; - if (this.hasNone) { + if (this.showNoneItem) { var prevNoneIndex = this.noneIndexInArray(value); var newNoneIndex = this.noneIndexInArray(newValue); if (prevNoneIndex > -1) { diff --git a/src/settings.ts b/src/settings.ts index 817bc044fe..7a36847c8d 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -515,6 +515,8 @@ export var settings = { * Default value: `"none"` */ noneItemValue: "none", + refuseItemValue: "refuse", + donotKnowItemValue: "donotknow", /** * An object whose properties specify the order of the special choice items (None, Other, Select All) in select-based questions. * diff --git a/tests/paneltests.ts b/tests/paneltests.ts index 01d44d028e..c5da3b5526 100644 --- a/tests/paneltests.ts +++ b/tests/paneltests.ts @@ -1178,7 +1178,7 @@ QUnit.test( "name": "cars", "title": "Dropdown", - "hasNone": true, + "showNoneItem": true, "colCount": 4, "choices": [ "Ford", @@ -1198,7 +1198,7 @@ QUnit.test( "title": "Checkbox", "hasSelectAll": true, - "hasNone": true, + "showNoneItem": true, "colCount": 4, "choices": [ "Ford", diff --git a/tests/questionDropdownTests.ts b/tests/questionDropdownTests.ts index 8a4b79a109..b2d9e77265 100644 --- a/tests/questionDropdownTests.ts +++ b/tests/questionDropdownTests.ts @@ -370,7 +370,7 @@ QUnit.test("readOnlyText default", assert => { "name": "q1", "placeholder": "click", "hasOther": true, - "hasNone": true, + "showNoneItem": true, "choices": [{ value: 1, text: "item 1" }, { value: 2, text: "item 2" }, { value: 3, text: "item 3" }] }] }; diff --git a/tests/question_baseselecttests.ts b/tests/question_baseselecttests.ts index a9163c5939..f6a3bc9cc5 100644 --- a/tests/question_baseselecttests.ts +++ b/tests/question_baseselecttests.ts @@ -145,7 +145,7 @@ QUnit.test("Check QuestionSelectBase and separateSpecialChoices option", functio choices: ["Item1", "Item2"], hasOther: true, hasSelectAll: true, - hasNone: true, + showNoneItem: true, colCount: 2 }, ], @@ -318,7 +318,7 @@ QUnit.test("check onShowingChoiceItem event", (assert) => { type: "radiogroup", name: "q1", choices: [{ value: "Item1", visibleIf: "1 = 2" }, "Item2", "Item3"], - hasNone: true, + showNoneItem: true, hasOther: true }] }); @@ -492,7 +492,7 @@ QUnit.test("checkbox vs valuePropertyName, check selectAll and none", (assert) = name: "q1", choices: ["apple", "banana", "orange"], valuePropertyName: "fruit", - hasNone: true, + showNoneItem: true, hasSelectAll: true } ] @@ -630,7 +630,7 @@ QUnit.test("checkbox and radio css", (assert) => { type: "radiogroup", name: "q1", choices: ["Item 1"], - hasNone: true + showNoneItem: true }, { type: "checkbox", @@ -638,7 +638,7 @@ QUnit.test("checkbox and radio css", (assert) => { choices: ["Item 1"], showClearButton: true, hasSelectAll: true, - hasNone: true + showNoneItem: true }] }); let question1 = survey.getAllQuestions()[0]; @@ -787,7 +787,7 @@ QUnit.test("check locOwner for items", (assert) => { QUnit.test("check renamed has... properties", (assert) => { const question = new QuestionCheckboxModel("q1"); - assert.notOk(question.hasNone); + assert.notOk(question.showNoneItem); assert.notOk(question.hasSelectAll); assert.notOk(question.hasOther); assert.notOk(question.hasComment); @@ -799,10 +799,10 @@ QUnit.test("check renamed has... properties", (assert) => { question.showNoneItem = true; assert.ok(question.showNoneItem); - assert.ok(question.hasNone); - question.hasNone = false; + assert.ok(question.showNoneItem); + question.showNoneItem = false; + assert.notOk(question.showNoneItem); assert.notOk(question.showNoneItem); - assert.notOk(question.hasNone); question.showSelectAllItem = true; assert.ok(question.showSelectAllItem); diff --git a/tests/question_matrixdynamictests.ts b/tests/question_matrixdynamictests.ts index 9545c441fb..a35b43a952 100644 --- a/tests/question_matrixdynamictests.ts +++ b/tests/question_matrixdynamictests.ts @@ -4773,7 +4773,7 @@ QUnit.test("showInMultipleColumns property, and visibleIf in choices", function name: "col2", cellType: "checkbox", showInMultipleColumns: true, - hasNone: true, + showNoneItem: true, choices: [ { value: "A", visibleIf: "{val1} = 1" }, { value: "B", visibleIf: "{val1} = 2" }, diff --git a/tests/question_tagbox_tests.ts b/tests/question_tagbox_tests.ts index 0d261ed4c0..41a2c6d95c 100644 --- a/tests/question_tagbox_tests.ts +++ b/tests/question_tagbox_tests.ts @@ -137,7 +137,7 @@ const jsonTagboxWithSelectAll = { type: "tagbox", name: "question1", hasOther: "true", - hasNone: "true", + showNoneItem: "true", hasSelectAll: "true", choices: [ "item1", diff --git a/tests/surveyquestiontests.ts b/tests/surveyquestiontests.ts index d67646b966..5543f3e598 100644 --- a/tests/surveyquestiontests.ts +++ b/tests/surveyquestiontests.ts @@ -1661,14 +1661,14 @@ QUnit.test("checkbox.renderedValue - storeOthersAsComment = false;", function ( ); assert.equal(question.comment, "X", "set comment"); }); -QUnit.test("checkbox.renderedValue - hasNone = true, Bug #1609", function ( +QUnit.test("checkbox.renderedValue - showNoneItem = true, Bug #1609", function ( assert ) { var survey = new SurveyModel(); survey.addNewPage("page1"); var question = new QuestionCheckboxModel("q"); question.choices = ["A", "B", "C", "D"]; - question.hasNone = true; + question.showNoneItem = true; survey.pages[0].addQuestion(question); question.value = ["A", "B"]; @@ -1686,14 +1686,14 @@ QUnit.test("checkbox.renderedValue - hasNone = true, Bug #1609", function ( ); }); QUnit.test( - "checkbox.renderedValue - hasNone = true and survey.storeOthersAsComment = false, Bug #1609", + "checkbox.renderedValue - showNoneItem = true and survey.storeOthersAsComment = false, Bug #1609", function (assert) { var survey = new SurveyModel(); survey.storeOthersAsComment = false; survey.addNewPage("page1"); var question = new QuestionCheckboxModel("q"); question.choices = ["A", "B", "C", "D"]; - question.hasNone = true; + question.showNoneItem = true; survey.pages[0].addQuestion(question); question.value = ["A", "B"]; @@ -3020,13 +3020,13 @@ QUnit.test("space in others does not work correctly , bug #1214", function ( ); }); -QUnit.test("Checkbox hasNone", function (assert) { +QUnit.test("Checkbox showNoneItem", function (assert) { var json = { elements: [ { type: "checkbox", name: "q1", - hasNone: true, + showNoneItem: true, choices: [1, 2, 3, 4, 5], }, ], @@ -3034,22 +3034,22 @@ QUnit.test("Checkbox hasNone", function (assert) { var survey = new SurveyModel(json); var q = survey.getQuestionByName("q1"); assert.equal(q.visibleChoices.length, 6, "5 items + none"); - q.hasNone = false; + q.showNoneItem = false; assert.equal(q.visibleChoices.length, 5, "none is removed"); - q.hasNone = true; + q.showNoneItem = true; assert.equal(q.visibleChoices.length, 6, "none is added"); q.value = [1, 2, "none"]; assert.deepEqual(q.value, ["none"], "we keep only none"); q.value = [1, "none"]; assert.deepEqual(q.value, [1], "none should gone"); }); -QUnit.test("Dropdown hasNone", function (assert) { +QUnit.test("Dropdown showNoneItem", function (assert) { var json = { elements: [ { type: "dropdown", name: "q1", - hasNone: true, + showNoneItem: true, choices: [1, 2, 3, 4, 5], }, ], @@ -3057,9 +3057,9 @@ QUnit.test("Dropdown hasNone", function (assert) { var survey = new SurveyModel(json); var q = survey.getQuestionByName("q1"); assert.equal(q.visibleChoices.length, 6, "5 items + none"); - q.hasNone = false; + q.showNoneItem = false; assert.equal(q.visibleChoices.length, 5, "none is removed"); - q.hasNone = true; + q.showNoneItem = true; assert.equal(q.visibleChoices.length, 6, "none is added"); }); @@ -3207,7 +3207,7 @@ QUnit.test("Test property hideIfChoicesEmpty", function (assert) { assert.equal(question.isVisible, false, "Choices are empty"); question.hasOther = true; question.hasSelectAll = true; - question.hasNone = true; + question.showNoneItem = true; assert.equal(question.isVisible, false, "Still choices are empty"); question.choices = [1, 2, 3]; assert.equal(question.isVisible, true, "Choices are not empty"); @@ -4578,7 +4578,7 @@ QUnit.test("Checkbox question getItemClass() + survey.onUpdateChoiceItemCss", fu name: "q1", storeOthersAsComment: false, hasSelectAll: true, - hasNone: true, + showNoneItem: true, choices: [1, 2], }, ], @@ -5295,7 +5295,7 @@ QUnit.test("Checkbox: Carry Forward and hasOther", function(assert) { assert.equal(q2.visibleChoices[2].text, "someText", "other text"); }); QUnit.test( - "choicesFromQuestion hasSelectAll, hasNone, hasOther properties, Bug#", + "choicesFromQuestion hasSelectAll, showNoneItem, hasOther properties, Bug#", function (assert) { var survey = new SurveyModel({ elements: [ @@ -5304,7 +5304,7 @@ QUnit.test( name: "q1", choices: [1, 2, 3], hasSelectAll: true, - hasNone: true, + showNoneItem: true, hasOther: true, }, { @@ -5312,7 +5312,7 @@ QUnit.test( name: "q2", choicesFromQuestion: "q1", hasSelectAll: true, - hasNone: true, + showNoneItem: true, hasOther: true, }, ], @@ -5607,7 +5607,7 @@ QUnit.test( false, "none not in list" ); - q1.hasNone = true; + q1.showNoneItem = true; assert.equal(q1.isItemInList(q1.visibleChoices[4]), true, "none in list"); assert.equal(q1.visibleChoices[5].value, "other", "index=5, other"); @@ -5679,7 +5679,7 @@ QUnit.test( "Do not show SelectAll+None+hasOther+new: 2" ); q1.hasSelectAll = true; - q1.hasNone = true; + q1.showNoneItem = true; q1.hasOther = true; assert.equal( q1.visibleChoices.length, @@ -5728,7 +5728,7 @@ QUnit.test("Creator V2: do not add choices from carry-forward in design mode", f settings.supportCreatorV2 = false; }); QUnit.test( - "Creator V2: Hide selectAll, hasNone and hasOther if this properties are invisible", + "Creator V2: Hide selectAll, showNoneItem and hasOther if this properties are invisible", function (assert) { var json = { elements: [ @@ -5741,7 +5741,7 @@ QUnit.test( }; settings.supportCreatorV2 = true; Serializer.findProperty("selectbase", "hasOther").visible = false; - Serializer.findProperty("selectbase", "hasNone").visible = false; + Serializer.findProperty("selectbase", "showNoneItem").visible = false; Serializer.findProperty("checkbox", "hasSelectAll").visible = false; var survey = new SurveyModel(); survey.setDesignMode(true); @@ -5753,7 +5753,7 @@ QUnit.test( "Hide SelectAll+None+hasOther and show only new: 3+4 - 3" ); Serializer.findProperty("selectbase", "hasOther").visible = true; - Serializer.findProperty("selectbase", "hasNone").visible = true; + Serializer.findProperty("selectbase", "showNoneItem").visible = true; Serializer.findProperty("checkbox", "hasSelectAll").visible = true; settings.supportCreatorV2 = false; }