diff --git a/packages/survey-angular-ui/src/questions/file.component.html b/packages/survey-angular-ui/src/questions/file.component.html index db8fac6a45..fa93cbeb0d 100644 --- a/packages/survey-angular-ui/src/questions/file.component.html +++ b/packages/survey-angular-ui/src/questions/file.component.html @@ -63,6 +63,6 @@ - + \ No newline at end of file diff --git a/packages/survey-vue3-ui/src/File.vue b/packages/survey-vue3-ui/src/File.vue index 79fc9fb80f..4cee54308c 100644 --- a/packages/survey-vue3-ui/src/File.vue +++ b/packages/survey-vue3-ui/src/File.vue @@ -167,8 +167,8 @@ > diff --git a/src/defaultCss/defaultV2Css.ts b/src/defaultCss/defaultV2Css.ts index e3761273a8..d66a0db4ce 100644 --- a/src/defaultCss/defaultV2Css.ts +++ b/src/defaultCss/defaultV2Css.ts @@ -544,6 +544,7 @@ export var defaultV2Css = { expression: "sd-expression", file: { root: "sd-file", + rootDragging: "sd-file--dragging", other: "sd-input sd-comment", placeholderInput: "sd-visuallyhidden", preview: "sd-file__preview", diff --git a/src/defaultV2-theme/blocks/sd-file.scss b/src/defaultV2-theme/blocks/sd-file.scss index 3626d062cb..238246b811 100644 --- a/src/defaultV2-theme/blocks/sd-file.scss +++ b/src/defaultV2-theme/blocks/sd-file.scss @@ -1,14 +1,17 @@ .sd-file { - min-height: calcSize(36); position: relative; font-size: calcFontSize(1); line-height: calcLineHeight(1.5); + min-height: calcSize(36); + box-sizing: border-box; + padding: 0 calcSize(6); .sv-action-bar { padding: calcSize(1) 0; justify-content: center; position: absolute; width: 100%; + left: 0; bottom: 0; .sv-action-bar-item { @@ -20,6 +23,7 @@ #fileIndex { .sv-action-bar-item { padding: calcSize(0.5) 0; + font-weight: 600; &:hover { background-color: $background; @@ -37,19 +41,22 @@ display: flex; flex-direction: column; position: absolute; + position: absolute; + left: calcSize(0); width: 100%; height: 100%; box-sizing: border-box; - border: 1px dashed $border; justify-content: center; align-items: center; + padding: 0 calcSize(8); + border: 1px dashed $border; } .sd-file__decorator--drag { + z-index: 1; border: 1px solid $primary; - box-shadow: inset 0 0 0 1px $primary; background: $primary-light; - z-index: 1; + box-shadow: inset 0 0 0 1px $primary; } .sd-file__no-file-chosen { @@ -57,7 +64,6 @@ } .sd-file__drag-area-placeholder { - padding: 0 calcSize(8); text-align: center; word-break: break-word; white-space: normal; @@ -67,7 +73,7 @@ } .sd-root-modern--mobile { - .sd-file__drag-area-placeholder { + .sd-file__decorator { padding: 0 calcSize(4); } } @@ -124,16 +130,15 @@ } .sd-file__list { - overflow: auto; display: flex; + gap: calcSize(4); box-sizing: content-box; flex-direction: row; align-items: stretch; - justify-content: space-between; + justify-content: center; padding: calcSize(10.5) 0; min-height: calcSize(15); max-height: calcSize(15); - position: absolute; width: 100%; } @@ -143,7 +148,7 @@ align-items: center; flex-direction: column; min-height: 100%; - margin: 0 auto; + margin: 0; .sd-file__default-image { width: calcSize(7); @@ -228,6 +233,8 @@ } .sd-file__list { + position: absolute; + left: 0; padding: 0; height: 100%; max-height: 100%; @@ -273,7 +280,7 @@ } .sd-file__drag-area { - position: absolute; + position: static; width: 100%; height: 100%; } \ No newline at end of file diff --git a/src/knockout/templates/question-file.html b/src/knockout/templates/question-file.html index 29bcd38ec5..10ce4e1708 100644 --- a/src/knockout/templates/question-file.html +++ b/src/knockout/templates/question-file.html @@ -59,8 +59,8 @@ - - + + diff --git a/src/question_file.ts b/src/question_file.ts index 258b27b37b..07717c8a84 100644 --- a/src/question_file.ts +++ b/src/question_file.ts @@ -6,7 +6,7 @@ import { EventBase, ComputedUpdater } from "./base"; import { UploadingFileError, ExceedSizeError } from "./error"; import { SurveyError } from "./survey-error"; import { CssClassBuilder } from "./utils/cssClassBuilder"; -import { confirmActionAsync, detectIEOrEdge, loadFileFromBase64 } from "./utils/utils"; +import { classesToSelector, confirmActionAsync, detectIEOrEdge, isElementVisible, loadFileFromBase64 } from "./utils/utils"; import { ActionContainer } from "./actions/container"; import { Action } from "./actions/action"; import { Helpers } from "./helpers"; @@ -39,6 +39,9 @@ export class QuestionFileModel extends Question { @property({ defaultValue: "empty" }) currentState: string; @property({ defaultValue: 0 }) indexToShow: number; + @property({ defaultValue: 1, onSet: (_, target) => { + target.updateFileNavigator(); + } }) pageSize: number; @property({ defaultValue: false }) containsMultiplyFiles: boolean; /** * Specifies whether users can capture and upload a photo. Applies only to mobile devices. @@ -47,13 +50,19 @@ export class QuestionFileModel extends Question { */ @property() allowCameraAccess: boolean; - public mobileFileNavigator: ActionContainer = new ActionContainer(); + public fileNavigator: ActionContainer = new ActionContainer(); protected prevFileAction: Action; protected nextFileAction: Action; protected fileIndexAction: Action; - get mobileFileNavigatorVisible(): boolean { - return this.isMobile && this.containsMultiplyFiles; + get fileNavigatorVisible(): boolean { + const isUploading = this.isUploading; + const containsMultipleFiles = this.containsMultiplyFiles; + const needToShowFileNavigator = this.pageSize < this.previewValue.length; + return !isUploading && containsMultipleFiles && needToShowFileNavigator && this.isDefaultV2Theme; + } + private get pagesCount() { + return Math.ceil(this.previewValue.length / this.pageSize); } constructor(name: string) { @@ -67,7 +76,7 @@ export class QuestionFileModel extends Question { id: "prevPage", iconSize: 16, action: () => { - this.indexToShow = this.previewValue.length && ((this.indexToShow - 1 + this.previewValue.length) % this.previewValue.length) || 0; + this.indexToShow = this.previewValue.length && ((this.indexToShow - 1 + this.pagesCount) % this.pagesCount) || 0; this.fileIndexAction.title = this.getFileIndexCaption(); } }); @@ -75,11 +84,11 @@ export class QuestionFileModel extends Question { id: "nextPage", iconSize: 16, action: () => { - this.indexToShow = this.previewValue.length && ((this.indexToShow + 1) % this.previewValue.length) || 0; + this.indexToShow = this.previewValue.length && ((this.indexToShow + 1) % this.pagesCount) || 0; this.fileIndexAction.title = this.getFileIndexCaption(); } }); - this.mobileFileNavigator.actions = [this.prevFileAction, this.fileIndexAction, this.nextFileAction]; + this.fileNavigator.actions = [this.prevFileAction, this.fileIndexAction, this.nextFileAction]; } protected updateElementCssCore(cssClasses: any): void { super.updateElementCssCore(cssClasses); @@ -88,16 +97,39 @@ export class QuestionFileModel extends Question { //this.mobileFileNavigator.cssClasses = this.survey.getCss().actionBar; } private getFileIndexCaption(): string { - return this.getLocalizationFormatString("indexText", this.indexToShow + 1, this.previewValue.length); + return this.getLocalizationFormatString("indexText", this.indexToShow + 1, this.pagesCount); + } + private updateFileNavigator() { + this.indexToShow = this.previewValue.length && ((this.indexToShow + this.pagesCount) % this.pagesCount) || 0; + this.fileIndexAction.title = this.getFileIndexCaption(); } + private prevPreviewLength = 0; private previewValueChanged() { - this.indexToShow = this.previewValue.length > 0 ? (this.indexToShow > 0 ? this.indexToShow - 1 : 0) : 0; + if(this.previewValue.length !== this.prevPreviewLength) { + if(this.previewValue.length > 0) { + if(this.prevPreviewLength > this.previewValue.length) { + this.indexToShow = this.indexToShow >= this.pagesCount && this.indexToShow > 0 ? this.pagesCount - 1 : this.indexToShow; + } else { + this.indexToShow = Math.floor(this.prevPreviewLength / this.pageSize); + } + } else { + this.indexToShow = 0; + } + } this.fileIndexAction.title = this.getFileIndexCaption(); this.containsMultiplyFiles = this.previewValue.length > 1; + if(this.previewValue.length > 0 && !this.calculatedGapBetweenItems && !this.calculatedItemWidth) { + setTimeout(() => { + this.processResponsiveness(0, this._width); + }); + } + this.prevPreviewLength = this.previewValue.length; } public isPreviewVisible(index: number) { - return !this.isMobile || index === this.indexToShow; + const isFileNavigatorVisible = this.fileNavigatorVisible; + const isPreviewVisible = (this.indexToShow * this.pageSize <= index && index < (this.indexToShow + 1) * this.pageSize); + return !isFileNavigatorVisible || isPreviewVisible; } public getType(): string { @@ -521,6 +553,7 @@ export class QuestionFileModel extends Question { public get fileRootCss(): string { return new CssClassBuilder() .append(this.cssClasses.root) + .append(this.cssClasses.rootDragging, this.isDragging) .append(this.cssClasses.single, !this.allowMultiple) .append(this.cssClasses.singleImage, !this.allowMultiple && this.isAnswered && this.canPreviewImage(this.value[0])) .append(this.cssClasses.mobile, this.isMobile) @@ -558,7 +591,54 @@ export class QuestionFileModel extends Question { super.endLoadingFromJson(); this.loadPreview(this.value); } - + protected needResponsiveness(): boolean { + return this.supportResponsiveness() && this.isDefaultV2Theme; + } + protected supportResponsiveness(): boolean { + return true; + } + protected getObservedElementSelector(): string { + return classesToSelector(this.cssClasses.dragArea); + } + private getFileListSelector(): string { + return classesToSelector(this.cssClasses.fileList); + } + private calcAvailableItemsCount = (availableWidth: number, itemWidth: number, gap: number): number => { + let itemsCount = Math.floor(availableWidth / (itemWidth + gap)); + if ((itemsCount + 1) * (itemWidth + gap) - gap <= availableWidth) itemsCount++; + return itemsCount; + }; + private calculatedGapBetweenItems: number; + private calculatedItemWidth: number; + private _width: number; + public triggerResponsiveness(hard?: boolean): void { + if(hard) { + this.calculatedGapBetweenItems = undefined; + this.calculatedItemWidth = undefined; + } + super.triggerResponsiveness(); + } + protected processResponsiveness(_: number, availableWidth: number): boolean { + this._width = availableWidth; + if(this.rootElement) { + if((!this.calculatedGapBetweenItems || !this.calculatedItemWidth) && this.allowMultiple) { + const fileListSelector = this.getFileListSelector(); + const fileListElement = fileListSelector ? this.rootElement.querySelector(this.getFileListSelector()) : undefined; + if(fileListElement) { + this.calculatedGapBetweenItems = Math.ceil(Number.parseFloat(window.getComputedStyle(fileListElement).gap)); + const firstVisibleItem = Array.from(fileListElement.children).filter((_, index) => this.isPreviewVisible(index))[0]; + if(firstVisibleItem) { + this.calculatedItemWidth = Math.ceil(Number.parseFloat(window.getComputedStyle(firstVisibleItem).width)); + } + } + } + } + if(this.calculatedGapBetweenItems && this.calculatedItemWidth) { + this.pageSize = this.calcAvailableItemsCount(availableWidth, this.calculatedItemWidth, this.calculatedGapBetweenItems); + return true; + } + return false; + } //#region // web-based methods private rootElement: HTMLElement; diff --git a/src/react/reactquestion_file.tsx b/src/react/reactquestion_file.tsx index 3f720911a3..668e3f7483 100644 --- a/src/react/reactquestion_file.tsx +++ b/src/react/reactquestion_file.tsx @@ -28,7 +28,7 @@ export class SurveyQuestionFile extends SurveyQuestionElementBase { this.question.cssClasses.removeButtonBottom ): null; - let mobileFileNavigator = this.question.mobileFileNavigatorVisible?():null; + let fileNavigator = this.question.fileNavigatorVisible?():null; fileInput = ( this.isDisplayMode ? ); diff --git a/src/vue/file.vue b/src/vue/file.vue index f75541497f..dcc57df861 100644 --- a/src/vue/file.vue +++ b/src/vue/file.vue @@ -167,8 +167,8 @@ > diff --git a/testCafe/questions/file.js b/testCafe/questions/file.js index dae48eb76c..3b93baf0b8 100644 --- a/testCafe/questions/file.js +++ b/testCafe/questions/file.js @@ -1,4 +1,4 @@ -import { frameworks, url, setOptions, initSurvey, getSurveyResult } from "../helper"; +import { frameworks, url, setOptions, initSurvey, getSurveyResult, url_test } from "../helper"; import { ClientFunction, fixture, Selector, test } from "testcafe"; // eslint-disable-next-line no-undef const assert = require("assert"); @@ -80,7 +80,7 @@ frameworks.forEach(framework => { assert.equal(surveyResult.image[1].name, "small_Dashka.jpg"); }); test("check clean button", async t => { - await ClientFunction(()=>{ + await ClientFunction(() => { window.survey.getAllQuestions()[0].needConfirmRemoveFile = false; })(); await t.setFilesToUpload("input[type=file]", "../resources/stub.txt"); @@ -210,3 +210,38 @@ frameworks.forEach(framework => { // assert(surveyResult.image.indexOf('image/jpeg') !== -1); // }); }); + +frameworks.forEach(framework => { + fixture`${framework} ${title}`.page`${url_test}defaultV2/${framework}`.beforeEach( + async t => { + await initSurvey(framework, { + elements: [ + { + type: "file", + title: "Please upload your photo", + name: "image", + storeDataAsText: true, + allowMultiple: true, + } + ] + }); + } + ); + + test("Check file navigator appear on smaller screen", async t => { + await t.resizeWindow(1920, 1080); + const fileNavigatorSelector = Selector(".sd-file .sv-action-bar"); + await t + .setFilesToUpload("input[type=file]", "../resources/stub.txt") + .setFilesToUpload("input[type=file]", "../resources/small_Dashka.jpg") + .setFilesToUpload("input[type=file]", "../resources/big_Dashka.jpg") + .expect(fileNavigatorSelector.exists) + .notOk() + .resizeWindow(620, 1080) + .expect(fileNavigatorSelector.exists) + .ok() + .expect(fileNavigatorSelector.find(".sv-action-bar-item__title").withText("1 of 2").exists).ok() + .resizeWindow(1920, 1080) + .expect(fileNavigatorSelector.exists).notOk(); + }); +}); \ No newline at end of file diff --git a/tests/markup/etalon_file.ts b/tests/markup/etalon_file.ts index 25bbbfe627..e3feb9381e 100644 --- a/tests/markup/etalon_file.ts +++ b/tests/markup/etalon_file.ts @@ -225,6 +225,41 @@ registerMarkupTests( ] }, snapshot: "file-2-zip-png", + initSurvey(survey) { + survey.getAllQuestions()[0]["pageSize"] = 2; + }, + before: () => StylesManager.applyTheme("defaultV2"), + after: () => StylesManager.applyTheme("default"), + }, + { + name: "Test multiply file question (defaultV2) with file navigator", + json: { + questions: [ + { + name: "name", + type: "file", + title: "Question title", + titleLocation: "hidden", + allowMultiple: true, + defaultValue: [ + { + "name": "item1.zip", + "type": "application/x-zip-compressed", + "content": "#item1.zip" + }, + { + "name": "item2.png", + "type": "image/png", + "content": "#item2.png" + } + ], + } + ] + }, + snapshot: "file-2-zip-png-file-navigator", + initSurvey(survey) { + survey.getAllQuestions()[0]["pageSize"] = 1; + }, before: () => StylesManager.applyTheme("defaultV2"), after: () => StylesManager.applyTheme("default"), }, @@ -255,6 +290,9 @@ registerMarkupTests( ] }, snapshot: "file-2-zip-png-ro", + initSurvey(survey) { + survey.getAllQuestions()[0]["pageSize"] = 2; + }, before: () => StylesManager.applyTheme("defaultV2"), after: () => StylesManager.applyTheme("default"), }, diff --git a/tests/markup/snapshots/file-2-zip-png-file-navigator.snap.html b/tests/markup/snapshots/file-2-zip-png-file-navigator.snap.html new file mode 100644 index 0000000000..703e334bcb --- /dev/null +++ b/tests/markup/snapshots/file-2-zip-png-file-navigator.snap.html @@ -0,0 +1,92 @@ +
+ +
+
+ Drag and drop a file here or click the button below and choose a file to upload. +
+ +
+
+ +
+ +
+ + + + +
+ Remove this file + + + + Remove this file + +
+
+
+ item1.zip +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/tests/questionFileTests.ts b/tests/questionFileTests.ts index 168cfcee22..d2a23ed2a6 100644 --- a/tests/questionFileTests.ts +++ b/tests/questionFileTests.ts @@ -5,6 +5,7 @@ import { surveyLocalization } from "../src/surveyStrings"; import { settings } from "../src/settings"; import { StylesManager } from "../src/stylesmanager"; import { Serializer } from "../src/jsonobject"; +import { defaultV2Css } from "../src/defaultCss/defaultV2Css"; export default QUnit.module("Survey_QuestionFile"); @@ -787,8 +788,8 @@ QUnit.test("Question File responsive", (assert) => { }, ], }; - StylesManager.applyTheme("default"); var survey = new SurveyModel(json); + survey.css = defaultV2Css; survey.locale = ""; var q1: QuestionFileModel = survey.getQuestionByName("image1"); @@ -802,46 +803,41 @@ QUnit.test("Question File responsive", (assert) => { }); q1.cssClasses.mobile = "m"; - assert.equal(q1.fileRootCss, "sv_q_file"); + assert.equal(q1.fileRootCss, "sd-file"); q1.isMobile = true; - assert.equal(q1.fileRootCss, "sv_q_file m"); - assert.equal(q1.mobileFileNavigatorVisible, false); - + q1.pageSize = 1; + assert.equal(q1.fileRootCss, "sd-file m"); + assert.equal(q1.fileNavigatorVisible, false); var files1: any = [{ name: "f1", type: "t1" }]; q1.loadFiles(files1); - assert.equal(q1.mobileFileNavigatorVisible, false); + assert.equal(q1.fileNavigatorVisible, false); var files2: any = [{ name: "f2", type: "t2", size: 100000 }]; q1.loadFiles(files2); - assert.equal(q1.mobileFileNavigatorVisible, true); + assert.equal(q1.fileNavigatorVisible, true); - assert.equal(q1["fileIndexAction"].title, "1 of 2"); - q1["nextFileAction"].action(); assert.equal(q1["fileIndexAction"].title, "2 of 2"); q1["nextFileAction"].action(); assert.equal(q1["fileIndexAction"].title, "1 of 2"); - q1["prevFileAction"].action(); + q1["nextFileAction"].action(); assert.equal(q1["fileIndexAction"].title, "2 of 2"); q1["prevFileAction"].action(); assert.equal(q1["fileIndexAction"].title, "1 of 2"); + q1["prevFileAction"].action(); + assert.equal(q1["fileIndexAction"].title, "2 of 2"); - assert.equal(q1.isPreviewVisible(0), true); - assert.equal(q1.isPreviewVisible(1), false); - - q1["nextFileAction"].action(); assert.equal(q1.isPreviewVisible(0), false); assert.equal(q1.isPreviewVisible(1), true); - q1.isMobile = false; + q1["nextFileAction"].action(); assert.equal(q1.isPreviewVisible(0), true); - assert.equal(q1.isPreviewVisible(1), true); + assert.equal(q1.isPreviewVisible(1), false); - q1.isMobile = true; - assert.equal(q1.mobileFileNavigatorVisible, true); + assert.equal(q1.fileNavigatorVisible, true); q1.clear(); - assert.equal(q1.mobileFileNavigatorVisible, false); + assert.equal(q1.fileNavigatorVisible, false); }); QUnit.test("QuestionFile inside a panel set value", async function(assert) { @@ -1199,11 +1195,13 @@ QUnit.test("File Question on Smaller Screens: navigation bar doesn't appear when }; const survey = new SurveyModel(json); const question = survey.getAllQuestions()[0]; + survey.css = defaultV2Css; question.isMobile = true; + question.pageSize = 1; assert.equal(question.indexToShow, 0); assert.equal(question["fileIndexAction"].title, "1 of 0"); assert.equal(question.containsMultiplyFiles, false); - assert.equal(question.mobileFileNavigatorVisible, false); + assert.equal(question.fileNavigatorVisible, false); survey.onDownloadFile.add(function (survey, options) { const timers = { @@ -1224,10 +1222,154 @@ QUnit.test("File Question on Smaller Screens: navigation bar doesn't appear when assert.equal(question.indexToShow, 0); assert.equal(question["fileIndexAction"].title, "1 of 3"); assert.equal(question.containsMultiplyFiles, true); - assert.equal(question.mobileFileNavigatorVisible, true); + assert.equal(question.fileNavigatorVisible, true); done(); }, 100); }); + +QUnit.test("Check file question navigator with different items count visible", (assert) => { + const json = { + showPreviewBeforeComplete: "showAnsweredQuestions", + elements: [ + { + type: "file", + name: "file", + storeDataAsText: false, + allowMultiple: true + } + ] + }; + const survey = new SurveyModel(json); + const question = survey.getAllQuestions()[0]; + survey.css = defaultV2Css; + question.pageSize = 3; + assert.equal(question.indexToShow, 0); + assert.equal(question["fileIndexAction"].title, "1 of 0"); + assert.equal(question.containsMultiplyFiles, false); + assert.equal(question.fileNavigatorVisible, false); + survey.onUploadFiles.add((survey, options) => { + options.callback( + "success", + options.files.map((file) => { + return { file: file, content: file.name + "_url" }; + }) + ); + }); + question.loadFiles([{ name: "f1", type: "t1" } as any]); + assert.equal(question.fileNavigatorVisible, false); + question.loadFiles([{ name: "f2", type: "t2" } as any]); + assert.equal(question.fileNavigatorVisible, false); + question.loadFiles([{ name: "f3", type: "t3" } as any]); + assert.equal(question.fileNavigatorVisible, false); + question.loadFiles([{ name: "f4", type: "t4" } as any]); + assert.equal(question.fileNavigatorVisible, true); + assert.equal(question.indexToShow, 1); + assert.equal(question["fileIndexAction"].title, "2 of 2"); + assert.notOk(question.isPreviewVisible(0)); + assert.notOk(question.isPreviewVisible(1)); + assert.notOk(question.isPreviewVisible(2)); + assert.ok(question.isPreviewVisible(3)); + question["prevFileAction"].action(); + assert.equal(question.indexToShow, 0); + assert.equal(question["fileIndexAction"].title, "1 of 2"); + assert.ok(question.isPreviewVisible(0)); + assert.ok(question.isPreviewVisible(1)); + assert.ok(question.isPreviewVisible(2)); + assert.notOk(question.isPreviewVisible(3)); + question["nextFileAction"].action(); + assert.equal(question.indexToShow, 1); + assert.equal(question["fileIndexAction"].title, "2 of 2"); + assert.notOk(question.isPreviewVisible(0)); + assert.notOk(question.isPreviewVisible(1)); + assert.notOk(question.isPreviewVisible(2)); + assert.ok(question.isPreviewVisible(3)); + question["nextFileAction"].action(); + assert.equal(question.indexToShow, 0); + assert.equal(question["fileIndexAction"].title, "1 of 2"); + assert.ok(question.isPreviewVisible(0)); + assert.ok(question.isPreviewVisible(1)); + assert.ok(question.isPreviewVisible(2)); + assert.notOk(question.isPreviewVisible(3)); + question["prevFileAction"].action(); + assert.equal(question.indexToShow, 1); + assert.equal(question["fileIndexAction"].title, "2 of 2"); + assert.notOk(question.isPreviewVisible(0)); + assert.notOk(question.isPreviewVisible(1)); + assert.notOk(question.isPreviewVisible(2)); + assert.ok(question.isPreviewVisible(3)); + + //check index position on load files + question.loadFiles([{ name: "f5", type: "t5" } as any, { name: "f6", type: "t6" } as any]); + assert.equal(question.indexToShow, 1); + assert.equal(question["fileIndexAction"].title, "2 of 2"); + question.loadFiles([{ name: "f7", type: "t7" } as any, { name: "f8", type: "t8" } as any]); + assert.equal(question.indexToShow, 2); + assert.equal(question["fileIndexAction"].title, "3 of 3"); + //check index position on deleting files + question.removeFile(question.previewValue[7].name); + assert.equal(question.indexToShow, 2); + assert.equal(question["fileIndexAction"].title, "3 of 3"); + question.removeFile(question.previewValue[6].name); + assert.equal(question.indexToShow, 1); + assert.equal(question["fileIndexAction"].title, "2 of 2"); + question.removeFile(question.previewValue[5].name); + assert.equal(question.indexToShow, 1); + assert.equal(question["fileIndexAction"].title, "2 of 2"); + question.removeFile(question.previewValue[4].name); + assert.equal(question.indexToShow, 1); + assert.equal(question["fileIndexAction"].title, "2 of 2"); + //check index position change on itemsCountToShow change + question.pageSize = 2; + assert.equal(question.indexToShow, 1); + assert.equal(question["fileIndexAction"].title, "2 of 2"); + assert.notOk(question.isPreviewVisible(0)); + assert.notOk(question.isPreviewVisible(1)); + assert.ok(question.isPreviewVisible(2)); + assert.ok(question.isPreviewVisible(3)); + question.pageSize = 1; + assert.equal(question.indexToShow, 1); + assert.equal(question["fileIndexAction"].title, "2 of 4"); + assert.notOk(question.isPreviewVisible(0)); + assert.ok(question.isPreviewVisible(1)); + assert.notOk(question.isPreviewVisible(2)); + assert.notOk(question.isPreviewVisible(3)); +}); +QUnit.test("Check file question processResponsiveness method", (assert) => { + const json = { + showPreviewBeforeComplete: "showAnsweredQuestions", + elements: [ + { + type: "file", + name: "file", + storeDataAsText: false, + allowMultiple: true + } + ] + }; + const survey = new SurveyModel(json); + const question = survey.getAllQuestions()[0]; + survey.css = defaultV2Css; + question["calculatedGapBetweenItems"] = 32; + question["calculatedItemWidth"] = 96; + question["processResponsiveness"](0, 400); + assert.equal(question.pageSize, 3); + + question["calculatedGapBetweenItems"] = 32; + question["calculatedItemWidth"] = 96; + question["processResponsiveness"](0, 250); + assert.equal(question.pageSize, 2); + + question["calculatedGapBetweenItems"] = 32; + question["calculatedItemWidth"] = 50; + question["processResponsiveness"](0, 250); + assert.equal(question.pageSize, 3); + + question["calculatedGapBetweenItems"] = 8; + question["calculatedItemWidth"] = 50; + question["processResponsiveness"](0, 250); + assert.equal(question.pageSize, 4); +}); + QUnit.test("QuestionFile download file content on preview", function(assert) { const survey = new SurveyModel({ elements: [ diff --git a/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile-next.png b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile-next.png index 159584a174..0a0ce8cde2 100644 Binary files a/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile-next.png and b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile-next.png differ diff --git a/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile-prev.png b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile-prev.png index 7699c57cbf..d489beebbf 100644 Binary files a/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile-prev.png and b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile-prev.png differ diff --git a/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile.png b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile.png index 6f897757b4..25fce93906 100644 Binary files a/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile.png and b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-mobile.png differ diff --git a/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-navigator.png b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-navigator.png new file mode 100644 index 0000000000..0c45bbecfb Binary files /dev/null and b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple-navigator.png differ diff --git a/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple.png b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple.png index d01519af2f..102e20793f 100644 Binary files a/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple.png and b/visualRegressionTests/tests/defaultV2/etalons/file-question-multiple.png differ diff --git a/visualRegressionTests/tests/defaultV2/file.ts b/visualRegressionTests/tests/defaultV2/file.ts index 1dea586279..c6ec6d47dd 100644 --- a/visualRegressionTests/tests/defaultV2/file.ts +++ b/visualRegressionTests/tests/defaultV2/file.ts @@ -53,6 +53,10 @@ frameworks.forEach(framework => { })(); await t.setFilesToUpload(Selector(".sd-file input"), ["files/Badger.png", "files/Bird.png", "files/Read Me.txt", "files/Flamingo.png"]); await takeElementScreenshot("file-question-multiple.png", questionRoot, t, comparer); + await t + .setFilesToUpload(Selector(".sd-file input"), ["files/SingleImage.jpg"]) + .click(Selector(".sd-file #prevPage")); + await takeElementScreenshot("file-question-multiple-navigator.png", questionRoot, t, comparer); }); }); @@ -81,10 +85,12 @@ frameworks.forEach(framework => { await ClientFunction(()=>{ (window as any).survey.resizeObserver.disconnect(); (window as any).survey.setIsMobile(false); + (window as any).survey.getAllQuestions()[0].resizeObserver.disconnect(); + (window as any).survey.getAllQuestions()[0].processResponsiveness = () => {}; + (window as any).survey.getAllQuestions()[0].pageSize = 1; (window as any).survey.getAllQuestions()[0].isMobile = true; })(); await t.setFilesToUpload(Selector(".sd-file input"), ["files/SingleImage.jpg"]); - const questionRoot = Selector(".sd-question"); await ClientFunction(()=>{ const question = (window as any).survey.getQuestionByName("file_question"); @@ -92,6 +98,11 @@ frameworks.forEach(framework => { question.clear(); })(); await t.setFilesToUpload(Selector(".sd-file input"), ["files/Badger.png", "files/Bird.png", "files/Read Me.txt", "files/Flamingo.png"]); + await ClientFunction(()=>{ + const question = (window as any).survey.getQuestionByName("file_question"); + question.indexToShow = 0; + question.fileIndexAction.title = question.getFileIndexCaption(); + })(); await takeElementScreenshot("file-question-multiple-mobile.png", questionRoot, t, comparer); await t.click(Selector(".sd-file #nextPage"));