Skip to content

Commit

Permalink
Allow to customize file preview component (#7062)
Browse files Browse the repository at this point in the history
* Allow to customize file preview component

* Fix angular build
  • Loading branch information
dk981234 committed Oct 3, 2023
1 parent 21e717b commit 718d5f3
Show file tree
Hide file tree
Showing 24 changed files with 185 additions and 132 deletions.
7 changes: 4 additions & 3 deletions packages/survey-angular-ui/src/angular-ui.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ import { MultipleTextRowComponent } from "./questions/multipletextrow.component"
import { LoadingIndicatorComponent } from "./angular-ui";
import { CoverComponent } from "./components/cover/cover.component";
import { CoverCellComponent } from "./components/cover/cover-cell.component";
import { ChooseFileBtn } from "./components/file-actions/choose-file.component";
import { ChooseFileBtn } from "./components/file/choose-file.component";
import { FilePreviewComponent } from "./components/file/file-preview.component";

@NgModule({
declarations: [
Expand All @@ -132,7 +133,7 @@ import { ChooseFileBtn } from "./components/file-actions/choose-file.component";
MultipleTextComponent, MultipleTextItemComponent, DynamicComponentDirective, RankingQuestionComponent, RankingItemComponent, PanelDynamicQuestionComponent, EmbeddedViewContentComponent, CustomWidgetComponent, MatrixCellComponent, MatrixTableComponent, MatrixDropdownComponent,
MatrixDynamicComponent, MatrixDetailButtonComponent, MatrixDynamicRemoveButtonComponent, MatrixDynamicDragDropIconComponent, MatrixRequiredHeader, ExpressionComponent, SafeResourceUrlPipe, BrandInfoComponent,
CustomQuestionComponent, CompositeQuestionComponent, ButtonGroupItemComponent, ButtonGroupQuestionComponent, MatrixRowComponent, ModalComponent, LogoImageComponent, SkeletonComponent, TimerPanelComponent, PaneldynamicRemoveButtonComponent,
NotifierComponent, ComponentsContainerComponent, MultipleTextRowComponent, LoadingIndicatorComponent, CoverComponent, CoverCellComponent, ChooseFileBtn
NotifierComponent, ComponentsContainerComponent, MultipleTextRowComponent, LoadingIndicatorComponent, CoverComponent, CoverCellComponent, ChooseFileBtn, FilePreviewComponent
],
imports: [
CommonModule, FormsModule
Expand All @@ -153,7 +154,7 @@ import { ChooseFileBtn } from "./components/file-actions/choose-file.component";
MultipleTextComponent, MultipleTextItemComponent, DynamicComponentDirective, RankingQuestionComponent, RankingItemComponent, PanelDynamicQuestionComponent, EmbeddedViewContentComponent, CustomWidgetComponent, MatrixCellComponent, MatrixTableComponent, MatrixDropdownComponent,
MatrixDynamicComponent, MatrixDetailButtonComponent, MatrixDynamicRemoveButtonComponent, MatrixDynamicDragDropIconComponent, MatrixRequiredHeader, ExpressionComponent, SafeResourceUrlPipe,
CustomQuestionComponent, CompositeQuestionComponent, ButtonGroupQuestionComponent, ModalComponent, LogoImageComponent, SkeletonComponent, TimerPanelComponent, PaneldynamicRemoveButtonComponent,
NotifierComponent, ComponentsContainerComponent, MultipleTextRowComponent, LoadingIndicatorComponent, CoverComponent, CoverCellComponent
NotifierComponent, ComponentsContainerComponent, MultipleTextRowComponent, LoadingIndicatorComponent, CoverComponent, CoverCellComponent, FilePreviewComponent
],
providers: [PopupService],
})
Expand Down
1 change: 1 addition & 0 deletions packages/survey-angular-ui/src/angular-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export * from "./panel.component";
export * from "./components/popup/modal-container.component";
export * from "./components/popup/popup.service";
export * from "./components/survey-actions/survey-nav-btn.component";
export * from "./components/file/file-preview.component";
export * from "./questions/matrix.component";
export * from "./components/svg-icon/svg-icon.component";
export * from "./questions/file.component";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<ng-template #template>
<div [class]="question.cssClasses.fileList || undefined">
<span *ngFor="let val of question.previewValue; index as index; trackBy: trackFilesFn"
[visible]="val && question.isPreviewVisible(index)" [class]="question.cssClasses.preview">
<div *ngIf="val.name && question.cssClasses.fileSign" [class]="question.cssClasses.fileSign">
<a (click)="question.doDownloadFile($event, val)" [attr.href]="val.content | safeUrl"
[attr.title]="val.name" [attr.download]="val.name" [style.width]="question.imageWidth">{{ val.name
}}</a>
</div>
<div [class]="question.cssClasses.imageWrapper">
<img *ngIf="question.canPreviewImage(val)" [attr.src]="val.content | safeUrl"
[style.height]="question.imageHeight" [style.width]="question.imageWidth" alt="File preview" />
<svg *ngIf="question.defaultImage(val)" [iconName]="question.cssClasses.defaultImageIconId"
[partCss]="question.cssClasses.defaultImage" [size]="'auto'" sv-ng-svg-icon></svg>
<div *ngIf="val.name && !question.isReadOnly" [class]="question.getRemoveButtonCss()"
(click)="question.doRemoveFile(val)">
<span [class]="question.cssClasses.removeFile">{{ question.removeFileCaption }}</span>
<svg *ngIf="question.cssClasses.removeFileSvgIconId" [title]="question.removeFileCaption"
[partCss]="question.cssClasses.removeFileSvg"
[iconName]="question.cssClasses.removeFileSvgIconId" [size]="'auto'" sv-ng-svg-icon></svg>
</div>
</div>
<div *ngIf="val.name && question.cssClasses.fileSignBottom" [class]="question.cssClasses.fileSignBottom">
<a (click)="question.doDownloadFile($event, val)" [attr.href]="val.content | safeUrl"
[attr.title]="val.name" [attr.download]="val.name" [style.width]="question.imageWidth">{{ val.name
}}</a>
</div>
</span>
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Action, QuestionFileModel } from "survey-core";
import { AngularComponentFactory } from "../../component-factory";
import { Component, Input } from "@angular/core";
import { EmbeddedViewContentComponent } from "../../embedded-view-content.component";
@Component({
selector: "sv-ng-file-preview",
templateUrl: "./file-preview.component.html"
})
export class FilePreviewComponent extends EmbeddedViewContentComponent {
@Input() question!: QuestionFileModel;
trackFilesFn: (index: number) => string = (index: number): string => {
return this.question.inputId + "_" + index;
}
}
AngularComponentFactory.Instance.registerComponent("sv-file-preview", FilePreviewComponent);
30 changes: 1 addition & 29 deletions packages/survey-angular-ui/src/questions/file.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,42 +28,14 @@
<ng-container *ngTemplateOutlet="fileCleanButton; context: { css: model.showRemoveButton }"></ng-container>
</ng-container>
<ng-container *ngIf="model.allowShowPreview">
<ng-container *ngTemplateOutlet="filePreview"></ng-container>
<ng-template [component]="{ name: 'sv-file-preview', data: { question: model } }"></ng-template>
</ng-container>
<ng-container *ngIf="model.showRemoveButtonBottom">
<ng-container *ngTemplateOutlet="fileCleanButton; context: { css: model.showRemoveButtonBottom }"></ng-container>
</ng-container>
<sv-action-bar *ngIf="model.fileNavigatorVisible" [model]="model.fileNavigator"></sv-action-bar>
</div>
</div>
<ng-template #filePreview>
<div [class]="model.cssClasses.fileList || undefined">
<span *ngFor="let val of model.previewValue; index as index; trackBy: trackFilesFn"
[visible]="val && model.isPreviewVisible(index)" [class]="model.cssClasses.preview">
<div *ngIf="val.name && model.cssClasses.fileSign" [class]="model.cssClasses.fileSign">
<a (click)="model.doDownloadFile($event, val)" [attr.href]="val.content | safeUrl" [attr.title]="val.name"
[attr.download]="val.name" [style.width]="model.imageWidth">{{ val.name }}</a>
</div>
<div [class]="model.cssClasses.imageWrapper">
<img *ngIf="model.canPreviewImage(val)" [attr.src]="val.content | safeUrl" [style.height]="model.imageHeight"
[style.width]="model.imageWidth" alt="File preview" />
<svg *ngIf="model.defaultImage(val)" [iconName]="model.cssClasses.defaultImageIconId"
[partCss]="model.cssClasses.defaultImage" [size]="'auto'" sv-ng-svg-icon></svg>
<div *ngIf="val.name && !model.isReadOnly" [class]="model.getRemoveButtonCss()"
(click)="model.doRemoveFile(val)">
<span [class]="model.cssClasses.removeFile">{{ model.removeFileCaption }}</span>
<svg *ngIf="model.cssClasses.removeFileSvgIconId" [title]="model.removeFileCaption"
[partCss]="model.cssClasses.removeFileSvg" [iconName]="model.cssClasses.removeFileSvgIconId" [size]="'auto'"
sv-ng-svg-icon></svg>
</div>
</div>
<div *ngIf="val.name && model.cssClasses.fileSignBottom" [class]="model.cssClasses.fileSignBottom">
<a (click)="model.doDownloadFile($event, val)" [attr.href]="val.content | safeUrl" [attr.title]="val.name"
[attr.download]="val.name" [style.width]="model.imageWidth">{{ val.name }}</a>
</div>
</span>
</div>
</ng-template>
<ng-template #fileCleanButton let-css="css">
<button type="button" [class]="css" (click)="model.doClean()">
<span>{{ model.clearButtonCaption }}</span>
Expand Down
6 changes: 1 addition & 5 deletions packages/survey-angular-ui/src/questions/file.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ import { AngularComponentFactory } from "../component-factory";
templateUrl: "./file.component.html",
styleUrls: []
})
export class FileQuestionComponent extends QuestionAngular<QuestionFileModel> {
trackFilesFn: (index: number) => string = (index: number): string => {
return this.model.inputId + "_" + index;
}
}
export class FileQuestionComponent extends QuestionAngular<QuestionFileModel> {}

AngularComponentFactory.Instance.registerComponent("file-question", FileQuestionComponent);
File renamed without changes.
4 changes: 2 additions & 2 deletions packages/survey-vue3-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@ import {
} from "survey-core";
import type { App } from "vue";
import FileCleanButton from "./FileCleanButton.vue";
import FilePreview from "./FilePreview.vue";
import FileVideo from "./FileVideo.vue";
import FileChooseButton from "./components/file-actions/FileChooseButton.vue";
import FileChooseButton from "./components/file/FileChooseButton.vue";
import FilePreview from "./components/file/FilePreview.vue";
export { useBase, useLocString, useQuestion } from "./base";

SurveyModel.platform = "vue3";
Expand Down
3 changes: 2 additions & 1 deletion src/entries/knockout-ui-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export * from "../knockout/components/tagbox/tagbox-item";
export * from "../knockout/components/tagbox/tagbox";
export * from "../knockout/components/cover/cover";
export * from "../knockout/components/cover/cover-cell";
export * from "../knockout/components/file-actions/choose-file";
export * from "../knockout/components/file/choose-file";
export * from "../knockout/components/file/file-preview";

export * from "../knockout/components/list/list";
export * from "../knockout/components/svg-icon/svg-icon";
Expand Down
3 changes: 2 additions & 1 deletion src/entries/react-ui-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export {
} from "../react/reactquestion_matrix";
export { SurveyQuestionHtml } from "../react/reactquestion_html";
export { SurveyQuestionFile } from "../react/reactquestion_file";
export { SurveyFileChooseButton } from "../react/components/file-actions/file-choose-button";
export { SurveyFileChooseButton } from "../react/components/file/file-choose-button";
export { SurveyFilePreview } from "../react/components/file/file-preview";
export { SurveyQuestionMultipleText } from "../react/reactquestion_multipletext";
export { SurveyQuestionRadiogroup, SurveyQuestionRadioItem } from "../react/reactquestion_radiogroup";
export { SurveyQuestionText } from "../react/reactquestion_text";
Expand Down
4 changes: 2 additions & 2 deletions src/entries/vue-ui-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ export { Dropdown } from "../vue/dropdown.vue";
export { DropdownSelect } from "../vue/dropdown-select.vue";
export { Tagbox } from "../vue/tagbox.vue";
export { File } from "../vue/file.vue";
export { FilePreview } from "../vue/file-preview.vue";
export { FilePreview } from "../vue/components/file/file-preview.vue";
export { FileCleanButton } from "../vue/file-clean-button.vue";
export { FileVideo } from "../vue/file-video.vue";
export { FileChooseButton } from "../vue/components/file-actions/file-choose-button.vue";
export { FileChooseButton } from "../vue/components/file/file-choose-button.vue";

export { MatrixCell } from "../vue/matrixcell.vue";
export { MatrixHeaderRequired } from "../vue/matrixheaderrequired.vue";
Expand Down
File renamed without changes.
25 changes: 25 additions & 0 deletions src/knockout/components/file/file-preview.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

<div data-bind="css: question.cssClasses.fileList, foreach: question.koData, visible: question.koHasValue">
<span data-bind="visible: question.isPreviewVisible($index()), css: question.cssClasses.preview">
<!-- ko template: { name: 'survey-question-file-sign', data: {question: question, item: $data, fileSignCss: question.cssClasses.fileSign} } --><!-- /ko -->
<div data-bind="css: question.cssClasses.imageWrapper">
<!-- ko if: question.canPreviewImage($data) -->
<img data-bind="attr: { src: $data.content }, style : { height: question.imageHeight, width: question.imageWidth }" alt="File preview">
<!-- /ko -->
<!-- ko if: question.defaultImage($data) -->
<!-- ko component: { name: 'sv-svg-icon', params: { css: question.cssClasses.defaultImage, iconName: question.cssClasses.defaultImageIconId, size: 'auto' } } --><!-- /ko -->
<!-- /ko -->
<!-- ko if: $data.name -->
<!-- ko ifnot: question.isReadOnly -->
<div data-bind="click: question.doremovefile, css: question.getRemoveButtonCss()">
<span data-bind="css: question.cssClasses.removeFile, text: question.removeFileCaption"></span>
<!-- ko if: question.cssClasses.removeFileSvgIconId -->
<!-- ko component: { name: 'sv-svg-icon', params: { css: question.cssClasses.removeFileSvg, title: question.removeFileCaption, iconName: question.cssClasses.removeFileSvgIconId, size: 'auto' } } --><!-- /ko -->
<!-- /ko -->
</div>
<!-- /ko -->
<!-- /ko -->
</div>
<!-- ko template: { name: 'survey-question-file-sign', data: {question: question, item: $data, fileSignCss: question.cssClasses.fileSignBottom} } --><!-- /ko -->
</span>
</div>
14 changes: 14 additions & 0 deletions src/knockout/components/file/file-preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as ko from "knockout";

const template = require("./file-preview.html");

export var SurveyFilePreview: any;

ko.components.register("sv-file-preview", {
viewModel: {
createViewModel: (params: any, componentInfo: any) => {
return params;
},
},
template: template,
});
40 changes: 7 additions & 33 deletions src/knockout/templates/question-file.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<!-- ko template: { name: 'survey-question-file-clean-button', data: {question: question, showRemoveButton: question.showRemoveButton} } --><!-- /ko -->
<!-- ko if: question.showPreview -->
<!-- ko if: question.koHasValue && question.allowShowPreview -->
<!-- ko template: { name: 'survey-question-file-preview', data: { question: question } } --><!-- /ko -->
<!-- ko component: { name: 'sv-file-preview', data: { question: question } } --><!-- /ko -->
<!-- /ko -->
<!-- /ko -->
<!-- ko template: { name: 'survey-question-file-clean-button', data: {question: question, showRemoveButton: question.showRemoveButtonBottom} } --><!-- /ko -->
Expand All @@ -57,13 +57,6 @@
</button>
<!-- /ko -->
</script>
<script type="text/html" id="survey-question-file-sign">
<!-- ko if: item.name && fileSignCss -->
<div data-bind="css: fileSignCss">
<a data-bind="style: { width: question.imageWidth }, click: question.dodownload, text: item.name, attr: { href: item.content, title: item.name, download: item.name }"></a>
</div>
<!-- /ko -->
</script>
<script type="text/html" id="survey-question-file-video">
<div data-bind="css: question.cssClasses.videoContainer">
<!-- ko component: { name: 'sv-action', params: { item: question.changeCameraAction } } --><!-- /ko -->
Expand All @@ -72,29 +65,10 @@
<!-- ko component: { name: 'sv-action', params: { item: question.takePictureAction } } --><!-- /ko -->
</div>
</script>
<script type="text/html" id="survey-question-file-preview">
<div data-bind="css: question.cssClasses.fileList, foreach: question.koData, visible: question.koHasValue">
<span data-bind="visible: question.isPreviewVisible($index()), css: question.cssClasses.preview">
<!-- ko template: { name: 'survey-question-file-sign', data: {question: question, item: $data, fileSignCss: question.cssClasses.fileSign} } --><!-- /ko -->
<div data-bind="css: question.cssClasses.imageWrapper">
<!-- ko if: question.canPreviewImage($data) -->
<img data-bind="attr: { src: $data.content }, style : { height: question.imageHeight, width: question.imageWidth }" alt="File preview">
<!-- /ko -->
<!-- ko if: question.defaultImage($data) -->
<!-- ko component: { name: 'sv-svg-icon', params: { css: question.cssClasses.defaultImage, iconName: question.cssClasses.defaultImageIconId, size: 'auto' } } --><!-- /ko -->
<!-- /ko -->
<!-- ko if: $data.name -->
<!-- ko ifnot: question.isReadOnly -->
<div data-bind="click: question.doremovefile, css: question.getRemoveButtonCss()">
<span data-bind="css: question.cssClasses.removeFile, text: question.removeFileCaption"></span>
<!-- ko if: question.cssClasses.removeFileSvgIconId -->
<!-- ko component: { name: 'sv-svg-icon', params: { css: question.cssClasses.removeFileSvg, title: question.removeFileCaption, iconName: question.cssClasses.removeFileSvgIconId, size: 'auto' } } --><!-- /ko -->
<!-- /ko -->
</div>
<!-- /ko -->
<!-- /ko -->
</div>
<!-- ko template: { name: 'survey-question-file-sign', data: {question: question, item: $data, fileSignCss: question.cssClasses.fileSignBottom} } --><!-- /ko -->
</span>
</div>
<script type="text/html" id="survey-question-file-sign">
<!-- ko if: item.name && fileSignCss -->
<div data-bind="css: fileSignCss">
<a data-bind="style: { width: question.imageWidth }, click: question.dodownload, text: item.name, attr: { href: item.content, title: item.name, download: item.name }"></a>
</div>
<!-- /ko -->
</script>
Loading

0 comments on commit 718d5f3

Please sign in to comment.