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
+
+
+
+
+
+
+
+
![File preview](#item2.png)
+
+ Remove this file
+
+
+
+
+
+
+
+
+
\ 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"));