Merge branch 'master' of http://10.81.13.221:6990/Web/next-ucap-messenger
This commit is contained in:
commit
05a52dd1d5
|
@ -39,6 +39,11 @@ import { DeviceType } from '@ucap-webmessenger/core';
|
|||
import { UnreadCountRequest } from 'projects/ucap-webmessenger-api-message/src/lib/apis/unread-count';
|
||||
import { map, catchError, tap } from 'rxjs/operators';
|
||||
import { MessageStatusCode } from '@ucap-webmessenger/api';
|
||||
import {
|
||||
EditMessageDialogComponent,
|
||||
EditMessageDialogResult,
|
||||
EditMessageDialogData
|
||||
} from '../dialogs/message/edit-message.dialog.component';
|
||||
|
||||
export enum MainMenu {
|
||||
Group = 'GROUP',
|
||||
|
@ -202,6 +207,34 @@ export class LeftSideComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
async onClickNewMessage() {
|
||||
const result = await this.dialogService.open<
|
||||
EditMessageDialogComponent,
|
||||
EditMessageDialogData,
|
||||
EditMessageDialogResult
|
||||
>(EditMessageDialogComponent, {
|
||||
width: '600px',
|
||||
data: {
|
||||
loginRes: this.loginRes
|
||||
}
|
||||
});
|
||||
|
||||
// if (!!result && !!result.choice && result.choice) {
|
||||
// if (!!result.selectedUserList && result.selectedUserList.length > 0) {
|
||||
// const userSeqs: number[] = [];
|
||||
// result.selectedUserList.map(user => userSeqs.push(user.seq));
|
||||
|
||||
// if (type === 'NORMAL') {
|
||||
// this.store.dispatch(ChatStore.openRoom({ userSeqList: userSeqs }));
|
||||
// } else if (type === 'TIMER') {
|
||||
// this.store.dispatch(
|
||||
// ChatStore.openRoom({ userSeqList: userSeqs, isTimeRoom: true })
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
onClickOpenProfile(userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN) {
|
||||
this.openProfile.emit(userInfo);
|
||||
}
|
||||
|
@ -249,16 +282,28 @@ export class LeftSideComponent implements OnInit, OnDestroy {
|
|||
];
|
||||
}
|
||||
break;
|
||||
// case MainMenu.Organization:
|
||||
// {
|
||||
|
||||
// }
|
||||
// break;
|
||||
// case MainMenu.Call:
|
||||
// {
|
||||
|
||||
// }
|
||||
// break;
|
||||
case MainMenu.Organization:
|
||||
{
|
||||
this.fabButtonShow = false;
|
||||
}
|
||||
break;
|
||||
case MainMenu.Message:
|
||||
{
|
||||
this.fabButtonShow = true;
|
||||
this.fabButtons = [
|
||||
{
|
||||
icon: 'add',
|
||||
tooltip: 'New Message',
|
||||
divisionType: 'MESSAGE_NEW'
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case MainMenu.Call:
|
||||
{
|
||||
this.fabButtonShow = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
this.fabButtonShow = false;
|
||||
|
@ -343,6 +388,12 @@ export class LeftSideComponent implements OnInit, OnDestroy {
|
|||
this.onClickNewChat('TIMER');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'MESSAGE_NEW':
|
||||
{
|
||||
this.onClickNewMessage();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<mat-card class="confirm-card mat-elevation-z">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
쪽지 보내기
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
새쪽지를 보내요.
|
||||
|
||||
<ucap-message-editor></ucap-message-editor>
|
||||
</mat-card-content>
|
||||
<mat-card-actions class="button-farm flex-row">
|
||||
<button mat-stroked-button (click)="onClickTest()" class="mat-primary">
|
||||
테스트
|
||||
</button>
|
||||
<button
|
||||
mat-stroked-button
|
||||
(click)="onClickChoice(false)"
|
||||
class="mat-primary"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
mat-flat-button
|
||||
[disabled]="getBtnValid()"
|
||||
(click)="onClickChoice(true)"
|
||||
class="mat-primary"
|
||||
>
|
||||
보내기
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
|
@ -0,0 +1,27 @@
|
|||
::ng-deep .mat-card-header-tex {
|
||||
margin: 0;
|
||||
}
|
||||
.confirm-card {
|
||||
min-width: 500px;
|
||||
.mat-card-content {
|
||||
}
|
||||
.button-farm {
|
||||
text-align: right;
|
||||
.mat-primary {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .mat-mini-fab .mat-button-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.contents {
|
||||
height: 380px;
|
||||
|
||||
.thumbnail {
|
||||
max-width: 250px;
|
||||
max-height: 250px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EditMessageDialogComponent } from './edit-message.dialog.component';
|
||||
|
||||
describe('app::layouts::messenger::EditMessageDialogComponent', () => {
|
||||
let component: EditMessageDialogComponent;
|
||||
let fixture: ComponentFixture<EditMessageDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [EditMessageDialogComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditMessageDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,99 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Inject,
|
||||
ViewChild,
|
||||
ElementRef
|
||||
} from '@angular/core';
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
MatSelectionList,
|
||||
MatSelectionListChange,
|
||||
MatDrawer
|
||||
} from '@angular/material';
|
||||
import { Observable, combineLatest, of } from 'rxjs';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { map, catchError, take } from 'rxjs/operators';
|
||||
|
||||
import * as AppStore from '@app/store';
|
||||
import * as SyncStore from '@app/store/messenger/sync';
|
||||
|
||||
import {
|
||||
DialogService,
|
||||
ConfirmDialogComponent,
|
||||
ConfirmDialogData,
|
||||
ConfirmDialogResult,
|
||||
SnackBarService,
|
||||
AlertDialogComponent,
|
||||
AlertDialogResult,
|
||||
AlertDialogData
|
||||
} from '@ucap-webmessenger/ui';
|
||||
import { GroupDetailData, UserInfo } from '@ucap-webmessenger/protocol-sync';
|
||||
import {
|
||||
DetailResponse,
|
||||
MessageType,
|
||||
DetailContent,
|
||||
DetailReceiver,
|
||||
ContentType,
|
||||
MessageDetailInfo,
|
||||
MessageApiService,
|
||||
RetrieveResourceFileRequest,
|
||||
CancelRequest
|
||||
} from '@ucap-webmessenger/api-message';
|
||||
import { DeviceType, MimeUtil, FileUtil } from '@ucap-webmessenger/core';
|
||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
|
||||
import { MessageStatusCode } from '@ucap-webmessenger/api';
|
||||
import { MessageEditorComponent } from 'projects/ucap-webmessenger-ui/src/lib/components/message-editor.component';
|
||||
|
||||
export interface EditMessageDialogData {
|
||||
loginRes: LoginResponse;
|
||||
detail?: DetailResponse;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: no-empty-interface
|
||||
export interface EditMessageDialogResult {}
|
||||
|
||||
export interface DownloadQueueForMessage extends DetailContent {
|
||||
downloadType: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-messenger-edit-message',
|
||||
templateUrl: './edit-message.dialog.component.html',
|
||||
styleUrls: ['./edit-message.dialog.component.scss']
|
||||
})
|
||||
export class EditMessageDialogComponent implements OnInit {
|
||||
@ViewChild(MessageEditorComponent, { static: false })
|
||||
editor?: MessageEditorComponent;
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<
|
||||
EditMessageDialogData,
|
||||
EditMessageDialogResult
|
||||
>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: EditMessageDialogData,
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||
private messageApiService: MessageApiService,
|
||||
private snackBarService: SnackBarService,
|
||||
private logger: NGXLogger,
|
||||
private store: Store<any>,
|
||||
private dialogService: DialogService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
getBtnValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
onClickChoice(choice: boolean): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
onClickTest() {
|
||||
console.log(this.editor.getContents());
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
import { MessageDetailDialogComponent } from './message-detail.dialog.component';
|
||||
import { EditMessageDialogComponent } from './edit-message.dialog.component';
|
||||
|
||||
export const DIALOGS = [MessageDetailDialogComponent];
|
||||
export const DIALOGS = [
|
||||
MessageDetailDialogComponent,
|
||||
EditMessageDialogComponent
|
||||
];
|
||||
|
|
|
@ -3,16 +3,10 @@ import {
|
|||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
MatSelectionList,
|
||||
MatSelectionListChange,
|
||||
MatDrawer
|
||||
} from '@angular/material';
|
||||
import { Observable, combineLatest, of } from 'rxjs';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { map, catchError, take } from 'rxjs/operators';
|
||||
|
||||
import * as AppStore from '@app/store';
|
||||
import * as SyncStore from '@app/store/messenger/sync';
|
||||
|
||||
import {
|
||||
DialogService,
|
||||
ConfirmDialogComponent,
|
||||
|
@ -23,7 +17,6 @@ import {
|
|||
AlertDialogResult,
|
||||
AlertDialogData
|
||||
} from '@ucap-webmessenger/ui';
|
||||
import { GroupDetailData, UserInfo } from '@ucap-webmessenger/protocol-sync';
|
||||
import {
|
||||
DetailResponse,
|
||||
MessageType,
|
||||
|
@ -40,13 +33,13 @@ import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
|||
import { NGXLogger } from 'ngx-logger';
|
||||
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
|
||||
import { MessageStatusCode } from '@ucap-webmessenger/api';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
export interface MessageDetailDialogData {
|
||||
detail: DetailResponse;
|
||||
loginRes: LoginResponse;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: no-empty-interface
|
||||
export interface MessageDetailDialogResult {
|
||||
returnType: string;
|
||||
messageInfo?: MessageDetailInfo;
|
||||
|
@ -91,7 +84,6 @@ export class MessageDetailDialogComponent implements OnInit {
|
|||
private messageApiService: MessageApiService,
|
||||
private snackBarService: SnackBarService,
|
||||
private logger: NGXLogger,
|
||||
private store: Store<any>,
|
||||
private dialogService: DialogService
|
||||
) {}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<div class="toolbar">
|
||||
<button mat-stroked-button (click)="onClickFileInput('attach')">
|
||||
<span class="mdi mdi-attachment"></span>
|
||||
</button>
|
||||
<button mat-stroked-button (click)="onClickFileInput('image')">
|
||||
<span class="mdi mdi-image"></span>
|
||||
</button>
|
||||
<input
|
||||
type="file"
|
||||
#fileInput
|
||||
style="display: none"
|
||||
(change)="onChangeFileInput()"
|
||||
/>
|
||||
<button mat-stroked-button (click)="test()">
|
||||
test
|
||||
</button>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div
|
||||
#contentArea
|
||||
id="contentArea"
|
||||
contentEditable="true"
|
||||
class="editor"
|
||||
></div>
|
||||
</div>
|
|
@ -0,0 +1,9 @@
|
|||
.container {
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
|
||||
.editor {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MessageEditorComponent } from './message-editor.component';
|
||||
|
||||
describe('MessageEditorComponent', () => {
|
||||
let component: MessageEditorComponent;
|
||||
let fixture: ComponentFixture<MessageEditorComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ MessageEditorComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MessageEditorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,197 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
AfterViewInit,
|
||||
HostListener
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-message-editor',
|
||||
templateUrl: './message-editor.component.html',
|
||||
styleUrls: ['./message-editor.component.scss']
|
||||
})
|
||||
export class MessageEditorComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('fileInput', { static: false })
|
||||
fileInput: ElementRef<HTMLInputElement>;
|
||||
|
||||
@ViewChild('contentArea', { static: true }) contentArea: ElementRef;
|
||||
|
||||
attachFileType: string;
|
||||
|
||||
fileIndex = 0;
|
||||
attachFiles: { file: File; idx: number }[] = [];
|
||||
imageFiles: { file: File; idx: number }[] = [];
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
setTimeout(() => {
|
||||
this.contentArea.nativeElement.focus();
|
||||
|
||||
document
|
||||
.querySelector('#contentArea')
|
||||
.addEventListener('paste', (event: ClipboardEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
const clipboardData = event.clipboardData;
|
||||
let pastedData = clipboardData.getData('Text');
|
||||
pastedData = this.convertHtmltoEntity(pastedData);
|
||||
clipboardData.setData('Text', pastedData);
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = pastedData;
|
||||
|
||||
this.attachElementNextFocused(div);
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector('#contentArea')
|
||||
.addEventListener('keyup', event => {
|
||||
if (
|
||||
document.querySelector('#contentArea').innerHTML === '' ||
|
||||
document.querySelector('#contentArea').innerHTML === '<br>'
|
||||
) {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = ' <br>';
|
||||
document.querySelector('#contentArea').innerHTML = '';
|
||||
this.attachElementNextFocused(div);
|
||||
}
|
||||
});
|
||||
|
||||
// init..
|
||||
if (document.querySelector('#contentArea').innerHTML === '') {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = ' <br>';
|
||||
this.attachElementNextFocused(div);
|
||||
}
|
||||
}, 700);
|
||||
}
|
||||
|
||||
onClickFileInput(type: string) {
|
||||
this.attachFileType = type;
|
||||
if (type === 'attach') {
|
||||
this.fileInput.nativeElement.setAttribute('multiple', 'true');
|
||||
this.fileInput.nativeElement.setAttribute('accept', '*.*');
|
||||
} else {
|
||||
this.fileInput.nativeElement.removeAttribute('multiple');
|
||||
this.fileInput.nativeElement.setAttribute('accept', 'image/*');
|
||||
}
|
||||
this.fileInput.nativeElement.click();
|
||||
}
|
||||
|
||||
onChangeFileInput() {
|
||||
const files: FileList = this.fileInput.nativeElement.files;
|
||||
|
||||
// tslint:disable-next-line: prefer-for-of
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
if (this.attachFileType === 'attach') {
|
||||
this.attachFiles.push({ file: files[i], idx: this.fileIndex });
|
||||
} else {
|
||||
this.imageFiles.push({ file: files[i], idx: this.fileIndex });
|
||||
this.addImageInInputField(files[i], this.fileIndex);
|
||||
}
|
||||
this.fileIndex++;
|
||||
}
|
||||
this.fileInput.nativeElement.value = '';
|
||||
}
|
||||
|
||||
getContents(): string {
|
||||
return 'this is contents';
|
||||
}
|
||||
|
||||
addImageInInputField(image: File, index: number) {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(image);
|
||||
reader.onloadend = () => {
|
||||
const img = document.createElement('img');
|
||||
img.setAttribute('src', reader.result.toString());
|
||||
img.setAttribute('data-seq', index.toString());
|
||||
|
||||
this.attachElementNextFocused(img);
|
||||
};
|
||||
}
|
||||
|
||||
attachElementNextFocused(el: HTMLElement) {
|
||||
if (window.getSelection) {
|
||||
const sel = window.getSelection();
|
||||
const selAnchorNode: Node = sel.anchorNode;
|
||||
const focusedEl = selAnchorNode.parentElement;
|
||||
|
||||
if (this.isParentIdCheck(focusedEl, 'contentArea')) {
|
||||
if (sel.rangeCount) {
|
||||
const range = sel.getRangeAt(0);
|
||||
|
||||
if (selAnchorNode.nodeType === Node.TEXT_NODE) {
|
||||
const content: string = focusedEl.textContent;
|
||||
|
||||
focusedEl.innerText =
|
||||
content.substr(0, range.startOffset) +
|
||||
el.textContent +
|
||||
content.substr(range.endOffset);
|
||||
} else if (
|
||||
selAnchorNode.nodeType === Node.ELEMENT_NODE &&
|
||||
focusedEl.id === 'contentArea'
|
||||
) {
|
||||
const selEl = selAnchorNode as HTMLElement;
|
||||
const content: string = selEl.textContent;
|
||||
|
||||
selEl.innerText =
|
||||
content.substr(0, range.startOffset) +
|
||||
el.textContent +
|
||||
content.substr(range.endOffset);
|
||||
} else {
|
||||
focusedEl.append(el);
|
||||
}
|
||||
} else {
|
||||
focusedEl.append(el);
|
||||
}
|
||||
} else {
|
||||
this.contentArea.nativeElement.appendChild(el);
|
||||
}
|
||||
} else {
|
||||
this.contentArea.nativeElement.appendChild(el);
|
||||
}
|
||||
}
|
||||
|
||||
isParentIdCheck(el: HTMLElement, id: string): boolean {
|
||||
if (el.id === id) {
|
||||
return true;
|
||||
} else {
|
||||
if (el.tagName === 'BODY' || el.tagName === 'body') {
|
||||
return false;
|
||||
} else {
|
||||
return this.isParentIdCheck(el.parentElement, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test(): void {
|
||||
if (!!this.contentArea) {
|
||||
const els: HTMLCollection = this.contentArea.nativeElement.children;
|
||||
|
||||
// tslint:disable-next-line: prefer-for-of
|
||||
for (let i = 0; i < els.length; i++) {
|
||||
console.log(this.convertEntitytoHtml(els[i].textContent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
convertHtmltoEntity(str: string): string {
|
||||
return str
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/\n/g, '<br>');
|
||||
}
|
||||
convertEntitytoHtml(str: string): string {
|
||||
return str
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/<br>/g, ' \n');
|
||||
}
|
||||
}
|
|
@ -53,6 +53,7 @@ import {
|
|||
import { SecondsToMinutesPipe } from './pipes/seconds-to-minutes.pipe';
|
||||
import { LinkyPipe } from './pipes/linky.pipe';
|
||||
import { StickerSelectorComponent } from './components/sticker-selector.component';
|
||||
import { MessageEditorComponent } from './components/message-editor.component';
|
||||
import { MatTabsModule } from '@angular/material';
|
||||
|
||||
const COMPONENTS = [
|
||||
|
@ -61,6 +62,7 @@ const COMPONENTS = [
|
|||
FileViewerComponent,
|
||||
ExpansionPanelComponent,
|
||||
StickerSelectorComponent,
|
||||
MessageEditorComponent,
|
||||
|
||||
BinaryViewerComponent,
|
||||
DocumentViewerComponent,
|
||||
|
|
Loading…
Reference in New Issue
Block a user