file upload is implemented

This commit is contained in:
병준 박 2019-11-05 13:46:17 +09:00
parent 5b9fa9f55c
commit 086a4556f8
17 changed files with 415 additions and 188 deletions

3
package-lock.json generated
View File

@ -14104,7 +14104,8 @@
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
"dev": true
},
"tslint": {
"version": "5.15.0",

View File

@ -6,25 +6,28 @@ import {
APIDecoder,
ParameterUtil,
StatusCode,
JsonAnalization
JsonAnalization,
APIFormDataEncoder
} from '@ucap-webmessenger/api';
import { JsonObject } from 'type-fest';
import { FileUploadItem } from '../models/file-upload-item';
export interface FileTalkSaveRequest extends APIRequest {
userSeq: string;
userSeq: number;
deviceType: DeviceType;
token: string;
file?: File;
file: File;
fileName?: string;
fileUploadItem: FileUploadItem;
thumb?: File;
voice?: boolean;
voiceTime?: string;
roomId?: string;
roomSeq?: string;
type?: string;
}
export interface FileTalkSaveResponse extends APIResponse {
roomID?: string;
roomSeq?: string;
fileName?: string;
fileExt?: string;
fileType?: string;
@ -49,19 +52,21 @@ const fileTalkSaveEncodeMap = {
thumb: 'thumb',
voice: 'p_voice',
voiceTime: 'p_voice_time',
roomId: 'p_room_id',
roomSeq: 'p_room_id',
type: 'p_type'
};
export const encodeFileTalkSave: APIEncoder<FileTalkSaveRequest> = (
export const encodeFileTalkSave: APIFormDataEncoder<FileTalkSaveRequest> = (
req: FileTalkSaveRequest
) => {
const extraParams: any = {};
extraParams.userSeq = String(req.userSeq);
if (!!req.voice) {
extraParams.voice = req.voice ? 'Y' : 'N';
}
return ParameterUtil.encode(fileTalkSaveEncodeMap, req, extraParams);
return ParameterUtil.encodeFormData(fileTalkSaveEncodeMap, req, extraParams);
};
export const decodeFileTalkSave: APIDecoder<FileTalkSaveResponse> = (
@ -71,7 +76,7 @@ export const decodeFileTalkSave: APIDecoder<FileTalkSaveResponse> = (
const json: JsonObject | Error = JsonAnalization.receiveAnalization(res);
return {
statusCode: json.StatusCode,
roomID: json.RoomID,
roomSeq: json.RoomID,
fileName: json.FileName,
fileExt: json.FileExt,
fileType: json.FileType,

View File

@ -4,32 +4,43 @@ import {
APIResponse,
APIEncoder,
APIDecoder,
ParameterUtil
ParameterUtil,
JsonAnalization,
StatusCode
} from '@ucap-webmessenger/api';
import { JsonObject } from 'type-fest';
export interface FileTalkShareRequest extends APIRequest {
userSeq: string;
deviceType: DeviceType;
token: string;
attachmentsSeq?: string;
roomId?: string;
roomSeq?: string;
synapKey?: string;
}
export interface FileTalkShareResponse extends APIResponse {
RoomID?: string;
FileName?: string;
FileExt?: string;
FileType?: string;
ThumbURL?: string;
AttSEQ?: string;
AttSize?: string;
AttRegDate?: string;
CompanyCode?: string;
SynapKey?: string;
roomSeq?: string;
fileName?: string;
fileExt?: string;
fileType?: string;
thumbnailUrl?: string;
attachmentSeq?: string;
attachmentSize?: string;
attachmentRegDate?: string;
companyCode?: string;
synapKey?: string;
returnJson?: any;
}
const fileTalkShareEncodeMap = {};
const fileTalkShareEncodeMap = {
userSeq: 'p_user_seq',
deviceType: 'p_device_type',
token: 'p_token',
attachmentsSeq: 'p_att_seq',
roomSeq: 'p_room_id',
synapKey: 'p_synap_key'
};
export const encodeFileTalkShare: APIEncoder<FileTalkShareRequest> = (
req: FileTalkShareRequest
@ -40,5 +51,26 @@ export const encodeFileTalkShare: APIEncoder<FileTalkShareRequest> = (
export const decodeFileTalkShare: APIDecoder<FileTalkShareResponse> = (
res: any
) => {
return {} as FileTalkShareResponse;
try {
const json: JsonObject | Error = JsonAnalization.receiveAnalization(res);
return {
statusCode: json.StatusCode,
roomSeq: json.RoomID,
fileName: json.FileName,
fileExt: json.FileExt,
fileType: json.FileType,
thumbnailUrl: json.ThumbURL,
attachmentSeq: json.AttSEQ,
attachmentSize: json.AttSize,
attachmentRegDate: json.AttRegDate,
companyCode: json.CompanyCode,
synapKey: json.SynapKey,
returnJson: res
} as FileTalkShareResponse;
} catch (e) {
return {
statusCode: StatusCode.Fail,
errorMessage: e
} as FileTalkShareResponse;
}
};

View File

@ -20,7 +20,7 @@ export interface MassTalkSaveRequest extends APIRequest {
export interface MassTalkSaveResponse extends APIResponse {
eventMassSeq?: string;
roomID?: string;
roomSeq?: string;
regDate?: string;
content?: string;
returnJson?: any;
@ -51,7 +51,7 @@ export const decodeMassTalkSave: APIDecoder<MassTalkSaveResponse> = (
content: json.Content,
eventMassSeq: json.EventMassSeq,
regDate: json.RegDate,
roomID: json.RoomID,
roomSeq: json.RoomID,
returnJson: res
} as MassTalkSaveResponse;
} catch (e) {

View File

@ -4,8 +4,11 @@ import {
APIResponse,
APIEncoder,
APIDecoder,
ParameterUtil
ParameterUtil,
JsonAnalization,
StatusCode
} from '@ucap-webmessenger/api';
import { JsonObject } from 'type-fest';
export interface TransMassTalkSaveRequest extends APIRequest {
userSeq: string;
@ -13,20 +16,29 @@ export interface TransMassTalkSaveRequest extends APIRequest {
token: string;
original?: string;
translation?: string;
roomId?: string;
roomSeq?: string;
locale: string;
}
export interface TransMassTalkSaveResponse extends APIResponse {
EventTransSEQ?: string;
RoomID?: string;
RegDate?: string;
Locale?: string;
Original?: string;
Translation?: string;
roomSeq?: string;
registrationDate?: string;
translationSeq?: string;
locale?: string;
original?: string;
translation?: string;
returnJson?: any;
}
const transMassTalkSaveEncodeMap = {};
const transMassTalkSaveEncodeMap = {
userSeq: 'p_user_seq',
deviceType: 'p_device_type',
token: 'p_token',
original: 'p_original',
translation: 'p_translation',
roomSeq: 'p_room_id',
locale: 'p_locale'
};
export const encodeTransMassTalkSave: APIEncoder<TransMassTalkSaveRequest> = (
req: TransMassTalkSaveRequest
@ -37,5 +49,22 @@ export const encodeTransMassTalkSave: APIEncoder<TransMassTalkSaveRequest> = (
export const decodeTransMassTalkSave: APIDecoder<TransMassTalkSaveResponse> = (
res: any
) => {
return {} as TransMassTalkSaveResponse;
try {
const json: JsonObject | Error = JsonAnalization.receiveAnalization(res);
return {
statusCode: json.StatusCode,
translationSeq: json.EventTransSEQ,
roomSeq: json.RoomID,
registrationDate: json.RegDate,
locale: json.Locale,
original: json.Original,
translation: json.Translation,
returnJson: res
} as TransMassTalkSaveResponse;
} catch (e) {
return {
statusCode: StatusCode.Fail,
errorMessage: e
} as TransMassTalkSaveResponse;
}
};

View File

@ -4,30 +4,42 @@ import {
APIResponse,
APIEncoder,
APIDecoder,
ParameterUtil
ParameterUtil,
JsonAnalization,
StatusCode
} from '@ucap-webmessenger/api';
import { JsonObject } from 'type-fest';
export interface TranslationSaveRequest extends APIRequest {
userSeq: string;
deviceType: DeviceType;
token: string;
roomId?: string;
roomSeq?: string;
original?: string;
srcLocale: string;
destLocale: string;
}
export interface TranslationSaveResponse extends APIResponse {
EventTransSeq?: string;
RoomID?: string;
RegDate?: string;
SrcLocale?: string;
DestLocale?: string;
Original?: string;
Translation?: string;
translationSeq?: string;
roomSeq?: string;
registrationDate?: string;
srcLocale?: string;
destLocale?: string;
original?: string;
translation?: string;
returnJson?: any;
}
const translationSaveEncodeMap = {};
const translationSaveEncodeMap = {
userSeq: 'p_user_seq',
deviceType: 'p_device_type',
token: 'p_token',
roomSeq: 'p_room_id',
original: 'p_original',
srcLocale: 'p_src_locale',
destLocale: 'p_dest_locale'
};
export const encodeTranslationSave: APIEncoder<TranslationSaveRequest> = (
req: TranslationSaveRequest
@ -38,5 +50,23 @@ export const encodeTranslationSave: APIEncoder<TranslationSaveRequest> = (
export const decodeTranslationSave: APIDecoder<TranslationSaveResponse> = (
res: any
) => {
return {} as TranslationSaveResponse;
try {
const json: JsonObject | Error = JsonAnalization.receiveAnalization(res);
return {
statusCode: json.StatusCode,
translationSeq: json.EventTransSEQ,
roomSeq: json.RoomID,
registrationDate: json.RegDate,
srcLocale: json.SrcLocale,
destLocale: json.DestLocale,
original: json.Original,
translation: json.Translation,
returnJson: res
} as TranslationSaveResponse;
} catch (e) {
return {
statusCode: StatusCode.Fail,
errorMessage: e
} as TranslationSaveResponse;
}
};

View File

@ -3,12 +3,11 @@ import {
HttpClient,
HttpEventType,
HttpResponse,
HttpRequest,
HttpProgressEvent
HttpRequest
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { map, filter } from 'rxjs/operators';
import { _MODULE_CONFIG } from '../types/token';
import { ModuleConfig } from '../types/module-config';
@ -115,21 +114,30 @@ export class CommonApiService {
public fileTalkSave(
req: FileTalkSaveRequest,
fileTalkSaveUrl?: string
): Observable<FileTalkSaveResponse | HttpProgressEvent> {
): Observable<FileTalkSaveResponse> {
const asa = encodeFileTalkSave(req);
const httpReq = new HttpRequest(
'POST',
!!fileTalkSaveUrl ? fileTalkSaveUrl : this.moduleConfig.urls.fileTalkSave,
encodeFileTalkSave(req),
{ reportProgress: true }
{ reportProgress: true, responseType: 'text' as 'json' }
);
const progress = req.fileUploadItem.uploadStart();
return this.httpClient.request(httpReq).pipe(
map(event => {
filter(event => {
if (event instanceof HttpResponse) {
return decodeFileTalkSave(event);
return true;
} else if (HttpEventType.UploadProgress === event.type) {
return event;
progress.next(Math.round((100 * event.loaded) / event.total));
}
return false;
}),
map((event: HttpResponse<any>) => {
req.fileUploadItem.uploadComplete();
return decodeFileTalkSave(event.body);
})
);
}

View File

@ -1,14 +1,14 @@
.current-head{
.current-head {
display: flex;
justify-content: center;
padding: 0 10px;
height: 60px;
h3{
h3 {
display: inline-flex;
padding-left: 10px;
align-items: center;
}
.btn-box{
.btn-box {
height: 100%;
margin-left: auto;
display: inline-flex;
@ -24,41 +24,41 @@
padding: 0;
font-size: 14px;
border-bottom: 1px solid #dddddd;
.searchbox{
width:100%;
height:100%;
.searchbox {
width: 100%;
height: 100%;
}
}
::ng-deep .searchbox{
.mat-form-field{
display:block;
.mat-form-field-wrapper{
::ng-deep .searchbox {
.mat-form-field {
display: block;
.mat-form-field-wrapper {
padding: 0;
padding-bottom:0 !important;
padding-bottom: 0 !important;
height: 100%;
.mat-form-field-flex{
.mat-form-field-flex {
height: 59px;
padding:0 20px;
padding: 0 20px;
align-items: center;
.mat-form-field-infix{
width:100%;
font-size:14px;
border:none;
.mat-form-field-infix {
width: 100%;
font-size: 14px;
border: none;
}
.mat-form-field-suffix{
.mat-icon{
line-height:24px;
.mat-form-field-suffix {
.mat-icon {
line-height: 24px;
}
}
}
}
}
.mat-form-field-appearance-legacy{
.mat-form-field-wrapper{
.mat-form-field-appearance-legacy {
.mat-form-field-wrapper {
padding: 0;
}
.mat-form-field-underline{
bottom:0;
.mat-form-field-underline {
bottom: 0;
background-color: unset !important;
}
}

View File

@ -81,7 +81,8 @@
fxFlex="1 1 auto"
class="chat-content"
#messageBoxContainer
ucapUiFileUploadFor
ucapFileUploadFor
[fileUploadQueue]="fileUploadQueue"
(fileSelected)="onFileSelected($event)"
(fileDragEnter)="onFileDragEnter($event)"
(fileDragOver)="onFileDragOver()"
@ -109,16 +110,11 @@
</ucap-chat-messages>
</perfect-scrollbar>
<!-- CHAT MESSAGES -->
<div
*ngIf="fileDragOver || (files && 0 < files.length)"
class="file-drop-zone-container"
>
<div class="file-drop-zone">
<ucap-ui-file-upload-queue
[(files)]="files"
[items]="fileItems"
></ucap-ui-file-upload-queue>
</div>
<div class="file-drop-zone-container">
<ucap-file-upload-queue
#fileUploadQueue
class="file-drop-zone"
></ucap-file-upload-queue>
</div>
</div>
<!-- / CHAT CONTENT -->
@ -128,6 +124,7 @@
<!-- REPLY FORM -->
<ucap-chat-form
#chatForm
[fileUploadQueue]="fileUploadQueue"
(send)="onSendMessage($event)"
(sendFiles)="onFileSelected($event)"
></ucap-chat-form>
@ -147,7 +144,7 @@
<mat-menu
#messageContextMenu="matMenu"
[hasBackdrop]="false"
(ucapUiClickOutside)="messageContextMenuTrigger.closeMenu()"
(ucapClickOutside)="messageContextMenuTrigger.closeMenu()"
>
<ng-template matMenuContent let-message="message" let-loginRes="loginRes">
<ng-container *ngIf="!isRecalledMessage(message.type)">

View File

@ -91,15 +91,16 @@
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.95);
background-color: transparent;
.file-drop-zone {
position: absolute;
background-color: rgb(180, 180, 180);
top: 10%;
left: 10%;
width: 80%;
height: 80%;
top: calc(100% - 200px);
left: 20%;
width: 60%;
height: 200px;
}
}
}

View File

@ -2,10 +2,8 @@ import {
Component,
OnInit,
OnDestroy,
AfterViewChecked,
ViewChild,
ElementRef,
AfterContentInit,
AfterViewInit
} from '@angular/core';
import {
@ -18,11 +16,12 @@ import {
ConfirmDialogResult,
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
AlertDialogResult,
FileUploadQueueComponent
} from '@ucap-webmessenger/ui';
import { Store, select } from '@ngrx/store';
import { NGXLogger } from 'ngx-logger';
import { Observable, Subscription } from 'rxjs';
import { Observable, Subscription, forkJoin, of } from 'rxjs';
import {
Info,
EventType,
@ -44,7 +43,7 @@ import {
UserSelectDialogType
} from '@app/types';
import { RoomInfo, UserInfo, RoomType } from '@ucap-webmessenger/protocol-room';
import { tap, take } from 'rxjs/operators';
import { tap, take, map, catchError } from 'rxjs/operators';
import {
FileInfo,
FormComponent as UCapUiChatFormComponent
@ -52,7 +51,12 @@ import {
import { KEY_VER_INFO } from '@app/types/ver-info.type';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { MatMenuTrigger } from '@angular/material';
import { CommonApiService } from '@ucap-webmessenger/api-common';
import {
CommonApiService,
FileUploadItem,
FileTalkSaveRequest,
FileTalkSaveResponse
} from '@ucap-webmessenger/api-common';
import {
CreateChatDialogComponent,
CreateChatDialogData,
@ -65,6 +69,7 @@ import {
} from '@app/layouts/common/dialogs/image-viewer.dialog.component';
import { CONST } from '@ucap-webmessenger/core';
import { PerfectScrollbarComponent } from 'ngx-perfect-scrollbar';
import { StatusCode } from '@ucap-webmessenger/api';
@Component({
selector: 'app-layout-messenger-messages',
@ -86,6 +91,9 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
@ViewChild('psChatContent', { static: true })
psChatContent: PerfectScrollbarComponent;
@ViewChild('fileUploadQueue', { static: true })
fileUploadQueue: FileUploadQueueComponent;
environmentsInfo: EnvironmentsInfo;
loginRes: LoginResponse;
@ -106,10 +114,6 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
isCopyableMessage = isCopyable;
isRecallableMessage = isRecallable;
fileDragOver = false;
files: File[];
fileItems: DataTransferItemList;
/** Timer 대화방의 대화 삭제를 위한 interval */
interval: any;
@ -185,7 +189,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
);
this.interval = setInterval(() => {
if (!!this.roomInfo.isTimeRoom) {
if (!!this.roomInfo && !!this.roomInfo.isTimeRoom) {
this.store.dispatch(EventStore.infoIntervalClear({}));
}
}, 1000);
@ -369,8 +373,6 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
onFileDragEnter(items: DataTransferItemList) {
this.logger.debug('onFileDragEnter', items);
this.fileDragOver = true;
this.fileItems = items;
}
onFileDragOver() {
@ -379,17 +381,64 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
onFileDragLeave() {
this.logger.debug('onFileDragLeave');
this.fileDragOver = false;
}
onFileSelected(files: File[]) {
this.logger.debug('onFileSelected', files);
if (!this.files) {
this.files = [];
}
this.files.push(...files);
onFileSelected(fileUploadItems: FileUploadItem[]) {
this.logger.debug('onFileSelected', fileUploadItems);
this.fileDragOver = false;
const allObservables: Observable<FileTalkSaveResponse>[] = [];
for (const fileUploadItem of fileUploadItems) {
const req: FileTalkSaveRequest = {
userSeq: this.loginRes.userSeq,
deviceType: this.environmentsInfo.deviceType,
token: this.loginRes.tokenString,
roomSeq: this.roomInfo.roomSeq,
file: fileUploadItem.file,
fileName: fileUploadItem.file.name,
fileUploadItem
};
allObservables.push(
this.commonApiService
.fileTalkSave(req, this.sessionVerInfo.uploadUrl)
.pipe(
map(res => {
if (!res) {
return;
}
if (StatusCode.Success === res.statusCode) {
return res;
} else {
throw res;
}
})
)
);
}
forkJoin(allObservables)
.pipe(take(1))
.subscribe(
resList => {
for (const res of resList) {
this.store.dispatch(
EventStore.send({
senderSeq: this.loginRes.userSeq,
req: {
roomSeq: this.roomInfo.roomSeq,
eventType: EventType.File,
sentMessage: res.returnJson
}
})
);
}
},
error => {},
() => {
this.fileUploadQueue.onUploadComplete();
}
);
}
onContextMenuMessage(params: { event: MouseEvent; message: Info }) {

View File

@ -65,7 +65,6 @@ import {
cancel,
cancelFailure,
forward,
forwardFailure,
forwardAfterRoomOpen,
sendMass,
sendMassFailure,
@ -418,7 +417,7 @@ export class Effects {
send({
senderSeq: action.senderSeq,
req: {
roomSeq: res.roomID,
roomSeq: res.roomSeq,
eventType: EventType.MassText,
sentMessage: res.returnJson
}

View File

@ -4,9 +4,12 @@ import {
Output,
EventEmitter,
ViewChild,
ElementRef
ElementRef,
Input
} from '@angular/core';
import { NgForm } from '@angular/forms';
import { FileUploadItem } from '@ucap-webmessenger/api-common';
import { FileUploadQueueComponent } from '@ucap-webmessenger/ui';
@Component({
selector: 'ucap-chat-form',
@ -14,11 +17,14 @@ import { NgForm } from '@angular/forms';
styleUrls: ['./form.component.scss']
})
export class FormComponent implements OnInit {
@Input()
fileUploadQueue: FileUploadQueueComponent;
@Output()
send = new EventEmitter<string>();
@Output()
sendFiles = new EventEmitter<File[]>();
sendFiles = new EventEmitter<FileUploadItem[]>();
@ViewChild('replyForm', { static: false })
replyForm: NgForm;
@ -53,6 +59,13 @@ export class FormComponent implements OnInit {
for (let i = 0; i < this.fileInput.nativeElement.files.length; i++) {
files.push(this.fileInput.nativeElement.files.item(i));
}
this.sendFiles.emit(files);
const fileUploadItems = FileUploadItem.fromFiles(files);
if (!!this.fileUploadQueue) {
this.fileUploadQueue.onFileSelected(fileUploadItems);
}
this.sendFiles.emit(fileUploadItems);
}
}

View File

@ -1,41 +1,31 @@
<div
fxLayout="row wrap"
fxFlex="100"
class="ucap-ui-file-upload-queue-container"
>
<div fxLayout="row wrap" fxFlex="100" class="ucap-file-upload-queue-container">
<div
fxLayout="column"
fxFlex="100"
fxFlex.gt-xs="100"
fxFlex.gt-md="25"
*ngFor="let file of uploadFiles"
*ngFor="let fileUploadItem of fileUploadItems"
>
<div fxLayout="row">
<div>
<mat-icon>image</mat-icon>
</div>
<div>{{ file.name }}</div>
<div (click)="onClickClear(file)">
<div>{{ fileUploadItem.file.name }}</div>
<!-- <div (click)="onClickClear(fileUploadItem)">
<mat-icon>clear</mat-icon>
</div>
</div> -->
</div>
<div fxLayout="row">
<mat-progress-bar mode="determinate" value="40"> </mat-progress-bar>
<mat-progress-bar
mode="determinate"
[value]="fileUploadItem.uploadingProgress$ | async"
>
</mat-progress-bar>
</div>
</div>
<div *ngIf="uploadItems" fxLayout="column">
<div>여기에 파일을 Drop하시면 업로드 됩니다.</div>
<div>
<div
fxLayout="row"
fxFlex="100"
fxFlex.gt-xs="20"
fxFlex.gt-md="25"
*ngFor="let item of uploadItems"
>
<mat-icon>image</mat-icon>
</div>
</div>
<div></div>
</div>
</div>

View File

@ -1,4 +1,4 @@
.ucap-ui-file-upload-queue-container {
.ucap-file-upload-queue-container {
width: 100%;
height: 100%;
}

View File

@ -1,40 +1,108 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import {
Component,
OnInit,
Input,
Output,
EventEmitter,
ElementRef,
AfterViewInit
} from '@angular/core';
import { NGXLogger } from 'ngx-logger';
import { FileUploadItem } from '@ucap-webmessenger/api-common';
@Component({
selector: 'ucap-ui-file-upload-queue',
selector: 'ucap-file-upload-queue',
templateUrl: './file-upload-queue.component.html',
styleUrls: ['./file-upload-queue.component.scss']
})
export class FileUploadQueueComponent implements OnInit {
@Output()
filesChange = new EventEmitter<File[]>();
export class FileUploadQueueComponent implements OnInit, AfterViewInit {
fileUploadItems: FileUploadItem[];
uploadItems: DataTransferItem[];
@Input() set files(files: File[]) {
this.uploadFiles = files;
this.uploadItems = undefined;
constructor(
private elementRef: ElementRef<HTMLElement>,
private logger: NGXLogger
) {}
ngOnInit() {}
ngAfterViewInit(): void {
this.changeStyleDisplay(false);
}
onDragEnter(items: DataTransferItemList): void {
if (!items || 0 === items.length) {
return;
}
uploadFiles: File[];
@Input() set items(items: DataTransferItemList) {
const uploadItems: DataTransferItem[] = [];
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < items.length; i++) {
uploadItems.push(items[i]);
}
this.uploadItems = [...uploadItems];
this.changeStyleDisplay(true);
}
uploadItems: DataTransferItem[];
constructor(private logger: NGXLogger) {}
ngOnInit() {}
onClickClear(file: File) {
this.uploadFiles = this.uploadFiles.filter(f => {
return f.name !== file.name && f.path !== file.path;
});
this.filesChange.emit(this.uploadFiles);
onDragLeave(): void {
this.changeStyleDisplay(false);
}
onDrop(fileUploadItems: FileUploadItem[]) {
if (!fileUploadItems || 0 === fileUploadItems.length) {
return;
}
this.fileUploadItems = fileUploadItems;
this.uploadItems = undefined;
}
onFileSelected(fileUploadItems: FileUploadItem[]): void {
if (!fileUploadItems || 0 === fileUploadItems.length) {
return;
}
this.fileUploadItems = fileUploadItems;
this.uploadItems = undefined;
this.changeStyleDisplay(true);
}
onUploadComplete(): void {
setTimeout(() => {
this.fileUploadItems = undefined;
this.changeStyleDisplay(false);
}, 1000);
}
isEventInElement(event: DragEvent): boolean {
const rect = this.elementRef.nativeElement.getBoundingClientRect();
// const rect: DOMRect = this.elementRef.nativeElement.getBoundingClientRect();
if (
event.pageX >= rect.left &&
event.pageX <= rect.left + rect.width &&
event.pageY >= rect.top &&
event.pageY <= rect.top + rect.height
) {
return true;
}
return false;
}
private changeStyleDisplay(show: boolean): void {
if (show || (!!this.fileUploadItems && 0 < this.fileUploadItems.length)) {
this.elementRef.nativeElement.style.display = '';
} else {
this.elementRef.nativeElement.style.display = 'none';
}
}
// onClickClear(fileUploadItem: FileUploadItem) {
// this.fileUploadItems = this.fileUploadItems.filter(f => {
// return (
// f.file.name !== fileUploadItem.file.name &&
// f.file.path !== fileUploadItem.file.path
// );
// });
// this.filesChange.emit(this.fileUploadItems);
// }
}

View File

@ -3,15 +3,22 @@ import {
ElementRef,
EventEmitter,
HostListener,
Output
Output,
Input,
AfterViewInit
} from '@angular/core';
import { NGXLogger } from 'ngx-logger';
import { FileUploadQueueComponent } from '../components/file-upload-queue.component';
import { FileUploadItem } from '@ucap-webmessenger/api-common';
@Directive({
selector: 'input[ucapUiFileUploadFor], div[ucapUiFileUploadFor]'
selector: 'input[ucapFileUploadFor], div[ucapFileUploadFor]'
})
export class FileUploadForDirective {
export class FileUploadForDirective implements AfterViewInit {
@Input()
fileUploadQueue: FileUploadQueueComponent;
@Output()
public fileDragEnter = new EventEmitter<DataTransferItemList>();
@ -22,12 +29,14 @@ export class FileUploadForDirective {
public fileDragLeave = new EventEmitter<void>();
@Output()
public fileSelected = new EventEmitter<File[]>();
public fileSelected = new EventEmitter<FileUploadItem[]>();
dragOver = false;
constructor(private elementRef: ElementRef, private logger: NGXLogger) {}
ngAfterViewInit(): void {}
@HostListener('window:dragenter', ['$event'])
public onDragEnter(event: DragEvent): any {
if (!this.isFileDrag(event.dataTransfer)) {
@ -37,6 +46,9 @@ export class FileUploadForDirective {
if (!this.dragOver) {
this.fileDragEnter.emit(event.dataTransfer.items);
this.dragOver = true;
if (!!this.fileUploadQueue) {
this.fileUploadQueue.onDragEnter(event.dataTransfer.items);
}
}
}
@ -46,7 +58,7 @@ export class FileUploadForDirective {
return;
}
if (this.isEventInElement(event)) {
if (this.fileUploadQueue.isEventInElement(event)) {
event.dataTransfer.dropEffect = 'copy';
} else {
event.dataTransfer.dropEffect = 'none';
@ -63,13 +75,16 @@ export class FileUploadForDirective {
if (event && event.pageX === 0 && event.pageY === 0) {
this.fileDragLeave.emit();
this.dragOver = false;
if (!!this.fileUploadQueue) {
this.fileUploadQueue.onDragLeave();
}
}
}
@HostListener('change')
public onChange(): any {
const files = this.elementRef.nativeElement.files;
this.fileSelected.emit(files);
this.fileSelected.emit(FileUploadItem.fromFiles(files));
this.elementRef.nativeElement.value = '';
}
@ -79,11 +94,15 @@ export class FileUploadForDirective {
return;
}
const files = event.dataTransfer.files;
this.fileSelected.emit(files);
const fileUploadItems = FileUploadItem.fromFiles(files);
this.fileSelected.emit(fileUploadItems);
event.preventDefault();
event.stopPropagation();
this.elementRef.nativeElement.value = '';
this.dragOver = false;
if (!!this.fileUploadQueue) {
this.fileUploadQueue.onDrop(fileUploadItems);
}
}
private isFileDrag(dataTransfer: DataTransfer): boolean {
@ -101,18 +120,4 @@ export class FileUploadForDirective {
return true;
}
private isEventInElement(event: DragEvent): boolean {
const rect: DOMRect = this.elementRef.nativeElement.getBoundingClientRect();
if (
event.pageX >= rect.left &&
event.pageX <= rect.left + rect.width &&
event.pageY >= rect.top &&
event.pageY <= rect.top + rect.height
) {
return true;
}
return false;
}
}