Skip to content

Commit

Permalink
Merge branch 'master' into features/6061-renanme-properties
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewtelnov authored Aug 11, 2023
2 parents 8189e2d + 23a1ebb commit bd2a8dc
Show file tree
Hide file tree
Showing 51 changed files with 513 additions and 244 deletions.
4 changes: 3 additions & 1 deletion docs/survey-localization.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ This article describes how to localize UI elements and contents of your survey.

### Available Languages

Survey UI is translated into over 50 languages. We ship translated strings as [dictionary files](https://github.com/surveyjs/survey-library/tree/master/src/localization). They are supported by the community and may be incomplete. Feel free to add missing translations to existing dictionaries or create new dictionaries for other languages. You can use English as a base dictionary: copy the file, replace English translations in it, and submit a pull request with the resulting file to the [survey-library](https://github.com/surveyjs/survey-library) repository.
Survey UI is translated into over 50 languages. We ship translated strings as [dictionary files](https://github.com/surveyjs/survey-library/tree/master/src/localization). They are supported by the community and may contain untranslated strings. To fill the gap, these strings are translated by <a href="https://learn.microsoft.com/en-us/azure/ai-services/translator/" target="_blank">Azure AI Translator by Microsoft</a>. Each dictionary file contains a log of machine translations at the end. You can use it to find individual machine-translated strings and revise them if required. Delete revised strings from the log to exclude them from machine translation.

You can also create new dictionaries for unsupported languages. Use English as a base dictionary: copy the file, replace English translations in it, and submit a pull request with the resulting file to the [survey-library](https://github.com/surveyjs/survey-library) repository.

### Enable Localization and Switch Between Locales

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class DropdownComponent extends BaseAngular implements OnInit {
if (!!this.inputElementRef?.nativeElement) {
const control: any = this.inputElementRef.nativeElement;
const newValue = this.model.inputStringRendered;
if (!Helpers.isTwoValueEquals(newValue, control.value, false, true)) {
if (!Helpers.isTwoValueEquals(newValue, control.value, false, true, false)) {
control.value = this.model.inputStringRendered || "";
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/survey-angular-ui/src/questions/file.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@
tabindex="0"
[class]="model.getChooseFileCss()"
[attr.for]="model.inputId"
[attr.aria-label]="model.chooseButtonCaption"
[attr.aria-label]="model.chooseButtonText"
[key2click]
>
<span>{{ model.chooseButtonCaption }}</span>
<svg *ngIf="model.cssClasses.chooseFileIconId" [title]="model.chooseButtonCaption" [iconName]="model.cssClasses.chooseFileIconId" [size]="'auto'" sv-ng-svg-icon></svg>
<span>{{ model.chooseButtonText }}</span>
<svg *ngIf="model.cssClasses.chooseFileIconId" [title]="model.chooseButtonText" [iconName]="model.cssClasses.chooseFileIconId" [size]="'auto'" sv-ng-svg-icon></svg>
</label>
<span
[class]="model.cssClasses.noFileChosen"
Expand Down
6 changes: 3 additions & 3 deletions packages/survey-vue3-ui/src/File.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@
tabindex="0"
:class="question.getChooseFileCss()"
:for="question.inputId"
v-bind:aria-label="question.chooseButtonCaption"
v-bind:aria-label="question.chooseButtonText"
v-key2click
>
<span>{{ question.chooseButtonCaption }}</span>
<span>{{ question.chooseButtonText }}</span>
<sv-svg-icon
v-if="question.cssClasses.chooseFileIconId"
:title="question.chooseButtonCaption"
:title="question.chooseButtonText"
:iconName="question.cssClasses.chooseFileIconId"
:size="'auto'"
></sv-svg-icon>
Expand Down
4 changes: 3 additions & 1 deletion packages/survey-vue3-ui/src/components/dropdown/Dropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ const updateInputDomElement = () => {
if (inputElement.value) {
const control: any = inputElement.value;
const newValue = model.value.inputStringRendered;
if (!Helpers.isTwoValueEquals(newValue, control.value)) {
if (
!Helpers.isTwoValueEquals(newValue, control.value, false, true, false)
) {
control.value = model.value.inputStringRendered;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/calculatedValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export class CalculatedValue extends Base {
if (!!this.expressionRunner) return;
this.expressionRunner = new ExpressionRunner(this.expression);
this.expressionRunner.onRunComplete = newValue => {
if (!Helpers.isTwoValueEquals(newValue, this.value, false, true)) {
if (!Helpers.isTwoValueEquals(newValue, this.value, false, true, false)) {
this.setValue(newValue);
}
this.unlocCalculation();
Expand Down
4 changes: 4 additions & 0 deletions src/defaultV2-theme/blocks/sd-row.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
margin-top: calcSize(2);
}

.sd-page__row.sd-row--compact {
margin-top: var(--sd-base-vertical-padding);
}

.sd-row:first-of-type {
margin-top: 0;
}
Expand Down
1 change: 1 addition & 0 deletions src/dropdownListModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ export class DropdownListModel extends Base {
}

public onClick(event: any): void {
if(this.question.readOnly) return;
this._popupModel.toggleVisibility();
this.focusItemOnClickAndPopup();
if (this.searchEnabled && !!event && !!event.target) {
Expand Down
5 changes: 5 additions & 0 deletions src/knockout/koquestion_file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ class QuestionFileImplementor extends QuestionImplementor {
return [];
})
);
this.setObservaleObj("ko", ko.observable<string>());
this.setObservaleObj("koInputTitle", ko.observable<string>());
this.setObservaleObj(
"koChooseFileCss",
ko.pureComputed(() => {
return this.question.getChooseFileCss();
})
);
this.setCallbackFunc("koGetChooseButtonText", () => {
this.question.koState();
return this.question.chooseButtonText;
});
this.setCallbackFunc("ondrop", (data: any, event: any) => {
this.question.onDrop(getOriginalEvent(event));
});
Expand Down
6 changes: 3 additions & 3 deletions src/knockout/templates/question-file.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
<span data-bind="css: question.cssClasses.dragAreaPlaceholder, text: question.dragAreaPlaceholder"></span>
<div data-bind="css: question.cssClasses.wrapper">
<!-- ko ifnot: isReadOnly -->
<label tabindex="0" role="button" data-bind="css: question.koChooseFileCss, key2click, attr: { for: question.inputId, 'aria-label': question.chooseButtonCaption }">
<span data-bind="text: question.chooseButtonCaption"></span>
<label tabindex="0" role="button" data-bind="css: question.koChooseFileCss, key2click, attr: { for: question.inputId, 'aria-label': question.koGetChooseButtonText() }">
<span data-bind="text: question.koGetChooseButtonText()"></span>
<!-- ko if: question.cssClasses.chooseFileIconId -->
<!-- ko component: { name: 'sv-svg-icon', params: { title: question.chooseButtonCaption, iconName: question.cssClasses.chooseFileIconId, size: 'auto' } } --><!-- /ko -->
<!-- ko component: { name: 'sv-svg-icon', params: { title: question.koGetChooseButtonText(), iconName: question.cssClasses.chooseFileIconId, size: 'auto' } } --><!-- /ko -->
<!-- /ko -->
</label>
<!-- /ko -->
Expand Down
1 change: 1 addition & 0 deletions src/localization/english.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export var englishStrings = {
clearCaption: "Clear",
signaturePlaceHolder: "Sign here",
chooseFileCaption: "Choose file",
replaceFileCaption: "Replace file",
removeFileCaption: "Remove this file",
booleanCheckedLabel: "Yes",
booleanUncheckedLabel: "No",
Expand Down
11 changes: 0 additions & 11 deletions src/panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ export class QuestionRowModel extends Base {
var preSetWidthElements = [];
for (var i = 0; i < this.elements.length; i++) {
var el = this.elements[i];
this.setElementMaxMinWidth(el);

if (el.isVisible) {
(<any>el).isSingleInRow = isSingleInRow;
Expand Down Expand Up @@ -182,16 +181,6 @@ export class QuestionRowModel extends Base {
}
}
}
public setElementMaxMinWidth(el: IElement): void {
if (
el.width &&
typeof el.width === "string" &&
el.width.indexOf("%") === -1
) {
el.minWidth = el.width;
el.maxWidth = el.width;
}
}

private getRenderedCalcWidth(
el: IElement,
Expand Down
11 changes: 6 additions & 5 deletions src/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1409,7 +1409,7 @@ export class Question extends SurveyElement<Question>
if (res) return res;
}
value = value == undefined ? this.createValueCopy() : value;
if (this.isValueEmpty(value)) return this.getDisplayValueEmpty();
if (this.isValueEmpty(value, !this.allowSpaceAsAnswer)) return this.getDisplayValueEmpty();
return this.getDisplayValueCore(keysAsText, value);
}
protected getDisplayValueCore(keyAsText: boolean, value: any): any {
Expand Down Expand Up @@ -1598,7 +1598,7 @@ export class Question extends SurveyElement<Question>
return this.defaultValue;
}
protected isDefaultValueEmpty(): boolean {
return !this.defaultValueExpression && this.isValueEmpty(this.defaultValue);
return !this.defaultValueExpression && this.isValueEmpty(this.defaultValue, !this.allowSpaceAsAnswer);
}
protected getDefaultRunner(runner: ExpressionRunner, expression: string): ExpressionRunner {
if (!runner && !!expression) {
Expand Down Expand Up @@ -1710,7 +1710,7 @@ export class Question extends SurveyElement<Question>
* Returns `true` if the question value is an empty string, array, or object or if it equals `undefined` or `null`.
*/
public isEmpty(): boolean {
return this.isValueEmpty(this.value);
return this.isValueEmpty(this.value, !this.allowSpaceAsAnswer);
}
public get isAnswered(): boolean {
return this.getPropertyValue("isAnswered");
Expand Down Expand Up @@ -1926,11 +1926,12 @@ export class Question extends SurveyElement<Question>
this.onCompletedAsyncValidators = null;
}
}
public allowSpaceAsAnswer: boolean;
private isValueChangedInSurvey = false;
protected allowNotifyValueChanged = true;
protected setNewValue(newValue: any): void {
if(this.isNewValueEqualsToValue(newValue)) return;
if(!this.isValueEmpty(newValue) && !this.isNewValueCorrect(newValue)) {
if(!this.isValueEmpty(newValue, !this.allowSpaceAsAnswer) && !this.isNewValueCorrect(newValue)) {
ConsoleWarnings.inCorrectQuestionValue(this.name, newValue);
return;
}
Expand All @@ -1946,7 +1947,7 @@ export class Question extends SurveyElement<Question>
}
protected isNewValueEqualsToValue(newValue: any): boolean {
const val = this.value;
if(!this.isTwoValueEquals(newValue, val)) return false;
if(!this.isTwoValueEquals(newValue, val, false, false)) return false;
const isObj = newValue === val && !!val && (Array.isArray(val) || typeof val === "object");
return !isObj;
}
Expand Down
8 changes: 7 additions & 1 deletion src/question_file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ export class QuestionFileModel extends Question {
@property({ localizable: { defaultStr: "confirmRemoveAllFiles" } }) confirmRemoveAllMessage: string;
@property({ localizable: { defaultStr: "noFileChosen" } }) noFileChosenCaption: string;
@property({ localizable: { defaultStr: "chooseFileCaption" } }) chooseButtonCaption: string;
@property({ localizable: { defaultStr: "replaceFileCaption" } }) replaceButtonCaption: string;
@property({ localizable: { defaultStr: "clearCaption" } }) clearButtonCaption: string;
@property({ localizable: { defaultStr: "removeFileCaption" } }) removeFileCaption: string;
@property({ localizable: { defaultStr: "loadingFile" } }) loadingFileTitle: string;
Expand All @@ -227,6 +228,11 @@ export class QuestionFileModel extends Question {
if (this.isEmpty()) return this.chooseFileTitle;
return " ";
}

public get chooseButtonText () {
return this.isEmpty() || this.allowMultiple ? this.chooseButtonCaption : this.replaceButtonCaption;
}

public clear(doneCallback?: () => void) {
if (!this.survey) return;
this.containsMultiplyFiles = false;
Expand Down Expand Up @@ -280,7 +286,7 @@ export class QuestionFileModel extends Question {
if (status === "success") {
var oldValue = this.value;
if (Array.isArray(oldValue)) {
this.value = oldValue.filter((f) => !Helpers.isTwoValueEquals(f, content, true));
this.value = oldValue.filter((f) => !Helpers.isTwoValueEquals(f, content, true, false, false));
} else {
this.value = undefined;
}
Expand Down
2 changes: 1 addition & 1 deletion src/question_paneldynamic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export class QuestionPanelDynamicItem implements ISurveyData, ISurveyImpl {
public setValue(name: string, newValue: any) {
const oldItemData = this.data.getPanelItemData(this);
const oldValue = !!oldItemData ? oldItemData[name] : undefined;
if (Helpers.isTwoValueEquals(newValue, oldValue, false, true)) return;
if (Helpers.isTwoValueEquals(newValue, oldValue, false, true, false)) return;
this.data.setPanelItemData(this, name, Helpers.getUnbindValue(newValue));
const questions = this.panel.questions;
for (var i = 0; i < questions.length; i++) {
Expand Down
2 changes: 1 addition & 1 deletion src/react/dropdown-base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export class SurveyQuestionDropdownBase<T extends Question> extends SurveyQuesti
if (!!this.inputElement) {
const control: any = this.inputElement;
const newValue = this.question.dropdownListModel.inputStringRendered;
if (!Helpers.isTwoValueEquals(newValue, control.value, false, true)) {
if (!Helpers.isTwoValueEquals(newValue, control.value, false, true, false)) {
control.value = this.question.dropdownListModel.inputStringRendered;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/react/reactquestion_element.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ export class SurveyQuestionUncontrolledElement<
}
updateValueOnEvent = (event: any) => {
if (
!Helpers.isTwoValueEquals(this.questionBase.value, event.target.value, false, true)
!Helpers.isTwoValueEquals(this.questionBase.value, event.target.value, false, true, false)
) {
this.setValueCore(event.target.value);
}
Expand All @@ -297,7 +297,7 @@ export class SurveyQuestionUncontrolledElement<
if (!!this.control) {
const control: any = this.control;
const newValue = this.getValueCore();
if (!Helpers.isTwoValueEquals(newValue, control.value, false, true)) {
if (!Helpers.isTwoValueEquals(newValue, control.value, false, true, false)) {
control.value = this.getValue(newValue);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/react/reactquestion_file.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ export class SurveyQuestionFile extends SurveyQuestionElementBase {
tabIndex={0}
className={this.question.getChooseFileCss()}
htmlFor={this.question.inputId}
aria-label={this.question.chooseButtonCaption}
aria-label={this.question.chooseButtonText}
>
<span>{this.question.chooseButtonCaption}</span>
{(!!this.question.cssClasses.chooseFileIconId) ? <SvgIcon title={this.question.chooseButtonCaption} iconName={this.question.cssClasses.chooseFileIconId} size={"auto"}></SvgIcon>: null }
<span>{this.question.chooseButtonText}</span>
{(!!this.question.cssClasses.chooseFileIconId) ? <SvgIcon title={this.question.chooseButtonText} iconName={this.question.cssClasses.chooseFileIconId} size={"auto"}></SvgIcon>: null }
</label>
);
if (this.question.isEmpty()) {
Expand Down
2 changes: 1 addition & 1 deletion src/react/tagbox-filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class TagboxFilterString extends SurveyElementBase<ITagboxFilterProps, an
if (!!this.inputElement) {
const control: any = this.inputElement;
const newValue = this.model.inputStringRendered;
if (!Helpers.isTwoValueEquals(newValue, control.value, false, true)) {
if (!Helpers.isTwoValueEquals(newValue, control.value, false, true, false)) {
control.value = this.model.inputStringRendered;
}
}
Expand Down
20 changes: 13 additions & 7 deletions src/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3461,7 +3461,7 @@ export class SurveyModel extends SurveyElementCore
this.doCurrentPageCompleteCore(doComplete);
}
};
if (this.checkErrorsMode === "onComplete") {
if (this.isValidateOnComplete) {
if (!this.isLastPage) return false;
return this.validate(true, true, func) !== true;
}
Expand Down Expand Up @@ -3777,7 +3777,10 @@ export class SurveyModel extends SurveyElementCore
* @see nextPage
*/
public completeLastPage(): boolean {
var res = this.doCurrentPageComplete(true);
if(this.isValidateOnComplete) {
this.cancelPreview();
}
let res = this.doCurrentPageComplete(true);
if (res) {
this.cancelPreview();
}
Expand Down Expand Up @@ -3810,7 +3813,7 @@ export class SurveyModel extends SurveyElementCore
*/
public showPreview(): boolean {
this.resetNavigationButton();
if (this.checkErrorsMode !== "onComplete") {
if (!this.isValidateOnComplete) {
if (this.hasErrorsOnNavigate(true)) return false;
if (this.doServerValidation(true, true)) return false;
}
Expand Down Expand Up @@ -4253,7 +4256,7 @@ export class SurveyModel extends SurveyElementCore
self.completeServerValidation(options, isPreview);
},
};
if (doComplete && this.checkErrorsMode === "onComplete") {
if (doComplete && this.isValidateOnComplete) {
options.data = this.data;
} else {
var questions = this.activePage.questions;
Expand All @@ -4277,7 +4280,7 @@ export class SurveyModel extends SurveyElementCore
(<EventBase<SurveyModel>>this.onServerValidateQuestions).isEmpty
)
return false;
if (!doComplete && this.checkErrorsMode === "onComplete") return false;
if (!doComplete && this.isValidateOnComplete) return false;
this.setIsValidatingOnServer(true);
const isFunc = typeof this.onServerValidateQuestions === "function";
this.serverValidationEventCount = !isFunc ? this.onServerValidateQuestions.length : 1;
Expand Down Expand Up @@ -4713,6 +4716,9 @@ export class SurveyModel extends SurveyElementCore
get isValidateOnValueChanged(): boolean {
return this.checkErrorsMode === "onValueChanged";
}
private get isValidateOnComplete(): boolean {
return this.checkErrorsMode === "onComplete";
}
matrixCellValidate(question: QuestionMatrixDropdownModelBase, options: MatrixCellValidateEvent): SurveyError {
options.question = question;
this.onMatrixCellValidate.fire(this, options);
Expand Down Expand Up @@ -5312,7 +5318,7 @@ export class SurveyModel extends SurveyElementCore
private checkQuestionErrorOnValueChanged(question: Question) {
if (
!this.isNavigationButtonPressed &&
(this.checkErrorsMode === "onValueChanged" ||
(this.isValidateOnValueChanged ||
question.getAllErrors().length > 0)
) {
this.checkQuestionErrorOnValueChangedCore(question);
Expand Down Expand Up @@ -6078,7 +6084,7 @@ export class SurveyModel extends SurveyElementCore
)
return;
var oldValue = this.getValue(name);
if (this.isValueEmpty(newValue)) {
if (this.isValueEmpty(newValue, false)) {
this.deleteDataValueCore(this.valuesHash, name);
} else {
newValue = this.getUnbindValue(newValue);
Expand Down
2 changes: 1 addition & 1 deletion src/vue/components/dropdown/dropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export class DropdownComponent extends BaseVue {
if (!!this.inputElement) {
const control: any = this.inputElement;
const newValue = this.model.inputStringRendered;
if (!Helpers.isTwoValueEquals(newValue, control.value)) {
if (!Helpers.isTwoValueEquals(newValue, control.value, false, true, false)) {
control.value = this.model.inputStringRendered;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/vue/file.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@
tabindex="0"
:class="question.getChooseFileCss()"
:for="question.inputId"
v-bind:aria-label="question.chooseButtonCaption"
v-bind:aria-label="question.chooseButtonText"
v-key2click
>
<span>{{ question.chooseButtonCaption }}</span>
<sv-svg-icon v-if="question.cssClasses.chooseFileIconId" :title="question.chooseButtonCaption" :iconName="question.cssClasses.chooseFileIconId" :size="'auto'"></sv-svg-icon>
<span>{{ question.chooseButtonText }}</span>
<sv-svg-icon v-if="question.cssClasses.chooseFileIconId" :title="question.chooseButtonText" :iconName="question.cssClasses.chooseFileIconId" :size="'auto'"></sv-svg-icon>
</label>
<span
:class="question.cssClasses.noFileChosen"
Expand Down
Loading

0 comments on commit bd2a8dc

Please sign in to comment.