From 7ee3e761819e2a10399c33e67634293f9982959a Mon Sep 17 00:00:00 2001 From: Alex ORLUC <alex.orluc@maarch.org> Date: Wed, 8 Apr 2020 11:47:32 +0200 Subject: [PATCH] FEAT #13441 TIME 9 edit template with onlyoffice + fix interceptor --- .../controllers/OnlyOfficeController.php | 6 +- .../administration/administration.module.ts | 113 ++-- .../template-administration.component.html | 140 +++-- .../template-administration.component.ts | 500 ++++++++++++------ .../template-file-editor-modal.component.html | 13 + .../template-file-editor-modal.component.scss | 0 .../template-file-editor-modal.component.ts | 36 ++ .../app/viewer/document-viewer.component.ts | 4 +- .../onlyoffice-viewer.component.html | 2 +- .../onlyoffice-viewer.component.ts | 13 +- .../service/auth-interceptor.service.ts | 2 +- 11 files changed, 531 insertions(+), 298 deletions(-) create mode 100644 src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.html create mode 100644 src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.scss create mode 100644 src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.ts diff --git a/src/app/contentManagement/controllers/OnlyOfficeController.php b/src/app/contentManagement/controllers/OnlyOfficeController.php index 86292e602e5..cb2974bc8cd 100644 --- a/src/app/contentManagement/controllers/OnlyOfficeController.php +++ b/src/app/contentManagement/controllers/OnlyOfficeController.php @@ -70,7 +70,11 @@ class OnlyOfficeController } $path = $body['objectId']; - $fileContent = file_get_contents($path); + + $fileContent = @file_get_contents($path); + if ($fileContent == false) { + return $response->withStatus(400)->withJson(['errors' => 'No content found']); + } } elseif ($body['objectType'] == 'templateModification') { $docserver = DocserverModel::getCurrentDocserver(['typeId' => 'TEMPLATES', 'collId' => 'templates', 'select' => ['path_template']]); $template = TemplateModel::getById(['id' => $body['objectId'], 'select' => ['template_path', 'template_file_name']]); diff --git a/src/frontend/app/administration/administration.module.ts b/src/frontend/app/administration/administration.module.ts index ab585337aba..5821c37ed7c 100755 --- a/src/frontend/app/administration/administration.module.ts +++ b/src/frontend/app/administration/administration.module.ts @@ -1,60 +1,63 @@ -import { NgModule } from '@angular/core'; +import { NgModule } from '@angular/core'; -import { SharedModule } from '../app-common.module'; +import { SharedModule } from '../app-common.module'; -import { AdministrationRoutingModule } from './administration-routing.module'; +import { AdministrationRoutingModule } from './administration-routing.module'; import { NgxChartsModule } from '@swimlane/ngx-charts'; -import { AdministrationComponent } from './home/administration.component'; -import { UsersAdministrationComponent, UsersAdministrationRedirectModalComponent } from './user/users-administration.component'; -import { AccountLinkComponent } from './user/account-link/account-link.component'; -import { GroupsAdministrationComponent, GroupsAdministrationRedirectModalComponent } from './group/groups-administration.component'; -import { UserAdministrationComponent, UserAdministrationRedirectModalComponent } from './user/user-administration.component'; -import { GroupAdministrationComponent } from './group/group-administration.component'; -import { IndexingAdministrationComponent } from './group/indexing/indexing-administration.component'; -import { BasketsAdministrationComponent } from './basket/baskets-administration.component'; -import { BasketAdministrationComponent, BasketAdministrationSettingsModalComponent, BasketAdministrationGroupListModalComponent } from './basket/basket-administration.component'; -import { EntitiesAdministrationComponent, EntitiesAdministrationRedirectModalComponent} from './entity/entities-administration.component'; -import { DiffusionModelsAdministrationComponent } from './diffusionModel/diffusionModels-administration.component'; -import { DiffusionModelAdministrationComponent } from './diffusionModel/diffusionModel-administration.component'; -import { DoctypesAdministrationComponent, DoctypesAdministrationRedirectModalComponent } from './doctype/doctypes-administration.component'; -import { StatusesAdministrationComponent } from './status/statuses-administration.component'; -import { StatusAdministrationComponent } from './status/status-administration.component'; -import { ActionsAdministrationComponent } from './action/actions-administration.component'; -import { ActionAdministrationComponent } from './action/action-administration.component'; -import { ParametersAdministrationComponent } from './parameter/parameters-administration.component'; -import { ParameterAdministrationComponent } from './parameter/parameter-administration.component'; -import { PrioritiesAdministrationComponent } from './priority/priorities-administration.component'; -import { PriorityAdministrationComponent } from './priority/priority-administration.component'; -import { HistoryAdministrationComponent } from './history/history-administration.component'; -import { HistoryBatchAdministrationComponent } from './history/batch/history-batch-administration.component'; -import { UpdateStatusAdministrationComponent } from './updateStatus/update-status-administration.component'; -import { NotificationsAdministrationComponent } from './notification/notifications-administration.component'; -import { NotificationAdministrationComponent } from './notification/notification-administration.component'; -import { ContactsGroupsAdministrationComponent } from './contact/group/contacts-groups-administration.component'; -import { ContactsGroupAdministrationComponent } from './contact/group/contacts-group-administration.component'; -import { ContactsParametersAdministrationComponent } from './contact/parameter/contacts-parameters-administration.component'; -import { VersionsUpdateAdministrationComponent } from './versionUpdate/versions-update-administration.component'; -import { DocserversAdministrationComponent } from './docserver/docservers-administration.component'; -import { DocserverAdministrationComponent } from './docserver/docserver-administration.component'; -import { TemplatesAdministrationComponent } from './template/templates-administration.component'; -import { TemplateAdministrationComponent, TemplateAdministrationCheckEntitiesModalComponent } from './template/template-administration.component'; -import { SecuritiesAdministrationComponent } from './security/securities-administration.component'; -import { SendmailAdministrationComponent } from './sendmail/sendmail-administration.component'; -import { ListAdministrationComponent } from './basket/list/list-administration.component'; -import { ShippingsAdministrationComponent } from './shipping/shippings-administration.component'; -import { ShippingAdministrationComponent } from './shipping/shipping-administration.component'; -import { CustomFieldsAdministrationComponent } from './customField/custom-fields-administration.component'; -import { IndexingModelAdministrationComponent } from './indexingModel/indexing-model-administration.component'; -import { IndexingModelsAdministrationComponent } from './indexingModel/indexing-models-administration.component'; -import { ContactsListAdministrationComponent, ContactsListAdministrationRedirectModalComponent} from './contact/list/contacts-list-administration.component'; -import { ContactsCustomFieldsAdministrationComponent } from './contact/customField/contacts-custom-fields-administration.component'; -import { ContactsPageAdministrationComponent } from './contact/page/contacts-page-administration.component'; -import { TagsAdministrationComponent } from './tag/tags-administration.component'; -import { TagAdministrationComponent } from './tag/tag-administration.component'; +import { AdministrationComponent } from './home/administration.component'; +import { UsersAdministrationComponent, UsersAdministrationRedirectModalComponent } from './user/users-administration.component'; +import { AccountLinkComponent } from './user/account-link/account-link.component'; +import { GroupsAdministrationComponent, GroupsAdministrationRedirectModalComponent } from './group/groups-administration.component'; +import { UserAdministrationComponent, UserAdministrationRedirectModalComponent } from './user/user-administration.component'; +import { GroupAdministrationComponent } from './group/group-administration.component'; +import { IndexingAdministrationComponent } from './group/indexing/indexing-administration.component'; +import { BasketsAdministrationComponent } from './basket/baskets-administration.component'; +import { BasketAdministrationComponent, BasketAdministrationSettingsModalComponent, BasketAdministrationGroupListModalComponent } from './basket/basket-administration.component'; +import { EntitiesAdministrationComponent, EntitiesAdministrationRedirectModalComponent } from './entity/entities-administration.component'; +import { DiffusionModelsAdministrationComponent } from './diffusionModel/diffusionModels-administration.component'; +import { DiffusionModelAdministrationComponent } from './diffusionModel/diffusionModel-administration.component'; +import { DoctypesAdministrationComponent, DoctypesAdministrationRedirectModalComponent } from './doctype/doctypes-administration.component'; +import { StatusesAdministrationComponent } from './status/statuses-administration.component'; +import { StatusAdministrationComponent } from './status/status-administration.component'; +import { ActionsAdministrationComponent } from './action/actions-administration.component'; +import { ActionAdministrationComponent } from './action/action-administration.component'; +import { ParametersAdministrationComponent } from './parameter/parameters-administration.component'; +import { ParameterAdministrationComponent } from './parameter/parameter-administration.component'; +import { PrioritiesAdministrationComponent } from './priority/priorities-administration.component'; +import { PriorityAdministrationComponent } from './priority/priority-administration.component'; +import { HistoryAdministrationComponent } from './history/history-administration.component'; +import { HistoryBatchAdministrationComponent } from './history/batch/history-batch-administration.component'; +import { UpdateStatusAdministrationComponent } from './updateStatus/update-status-administration.component'; +import { NotificationsAdministrationComponent } from './notification/notifications-administration.component'; +import { NotificationAdministrationComponent } from './notification/notification-administration.component'; +import { ContactsGroupsAdministrationComponent } from './contact/group/contacts-groups-administration.component'; +import { ContactsGroupAdministrationComponent } from './contact/group/contacts-group-administration.component'; +import { ContactsParametersAdministrationComponent } from './contact/parameter/contacts-parameters-administration.component'; +import { VersionsUpdateAdministrationComponent } from './versionUpdate/versions-update-administration.component'; +import { DocserversAdministrationComponent } from './docserver/docservers-administration.component'; +import { DocserverAdministrationComponent } from './docserver/docserver-administration.component'; +import { TemplatesAdministrationComponent } from './template/templates-administration.component'; +import { TemplateAdministrationComponent, TemplateAdministrationCheckEntitiesModalComponent } from './template/template-administration.component'; +import { SecuritiesAdministrationComponent } from './security/securities-administration.component'; +import { SendmailAdministrationComponent } from './sendmail/sendmail-administration.component'; +import { ListAdministrationComponent } from './basket/list/list-administration.component'; +import { ShippingsAdministrationComponent } from './shipping/shippings-administration.component'; +import { ShippingAdministrationComponent } from './shipping/shipping-administration.component'; +import { CustomFieldsAdministrationComponent } from './customField/custom-fields-administration.component'; +import { IndexingModelAdministrationComponent } from './indexingModel/indexing-model-administration.component'; +import { IndexingModelsAdministrationComponent } from './indexingModel/indexing-models-administration.component'; +import { ContactsListAdministrationComponent, ContactsListAdministrationRedirectModalComponent } from './contact/list/contacts-list-administration.component'; +import { ContactsCustomFieldsAdministrationComponent } from './contact/customField/contacts-custom-fields-administration.component'; +import { ContactsPageAdministrationComponent } from './contact/page/contacts-page-administration.component'; +import { TagsAdministrationComponent } from './tag/tags-administration.component'; +import { TagAdministrationComponent } from './tag/tag-administration.component'; +import { TemplateFileEditorModalComponent } from './template/templateFileEditorModal/template-file-editor-modal.component'; + + @NgModule({ - imports: [ + imports: [ SharedModule, NgxChartsModule, AdministrationRoutingModule @@ -115,7 +118,8 @@ import { TagAdministrationComponent } from './tag/tag-administratio ContactsCustomFieldsAdministrationComponent, ContactsPageAdministrationComponent, TagsAdministrationComponent, - TagAdministrationComponent + TagAdministrationComponent, + TemplateFileEditorModalComponent ], entryComponents: [ UsersAdministrationRedirectModalComponent, @@ -127,7 +131,8 @@ import { TagAdministrationComponent } from './tag/tag-administratio DoctypesAdministrationRedirectModalComponent, ContactsListAdministrationRedirectModalComponent, TemplateAdministrationCheckEntitiesModalComponent, - AccountLinkComponent + AccountLinkComponent, + TemplateFileEditorModalComponent ], }) -export class AdministrationModule {} +export class AdministrationModule { } diff --git a/src/frontend/app/administration/template/template-administration.component.html b/src/frontend/app/administration/template/template-administration.component.html index 1f872f92436..3a3b3f93f49 100755 --- a/src/frontend/app/administration/template/template-administration.component.html +++ b/src/frontend/app/administration/template/template-administration.component.html @@ -2,8 +2,8 @@ <ng-template #adminMenuTemplate> <mat-nav-list *ngIf="!creationMode && !loading"> <h3 mat-subheader>{{lang.actions}}</h3> - <a mat-list-item [disableRipple]="lockFound || template.template_target == 'acknowledgementReceipt'" - [class.disabled]="lockFound || template.template_target == 'acknowledgementReceipt'" + <a mat-list-item [disableRipple]="lockFound || template.target == 'acknowledgementReceipt'" + [class.disabled]="lockFound || template.target == 'acknowledgementReceipt'" (click)="duplicateTemplate()"> <mat-icon color="primary" mat-list-icon class="fa fa-copy"></mat-icon> <p mat-line> @@ -36,19 +36,19 @@ <div class="form-group"> <div class="col-sm-12"> <mat-form-field> - <input matInput [(ngModel)]="template.template_label" required - name="template_label" id="template_label" title="{{lang.templateName}}" - type="text" placeholder="{{lang.templateName}}" maxlength="255"> + <input matInput name="label" [(ngModel)]="template.label" + title="{{lang.templateName}}" type="text" + placeholder="{{lang.templateName}}" maxlength="255" required> </mat-form-field> </div> </div> <div class="form-group"> <div class="col-sm-12"> <mat-form-field> - <textarea matInput [(ngModel)]="template.template_comment" required - name="template_comment" id="template_comment" - placeholder="{{lang.description}}" title="{{lang.description}}" - matTextareaAutosize matAutosizeMinRows="2" matAutosizeMaxRows="5"> + <textarea matInput name="description" [(ngModel)]="template.description" + name="template_comment" placeholder="{{lang.description}}" + title="{{lang.description}}" matTextareaAutosize matAutosizeMinRows="2" + matAutosizeMaxRows="5" required> </textarea> </mat-form-field> </div> @@ -56,21 +56,17 @@ <div class="form-group"> <div class="col-sm-12"> <mat-form-field> - <mat-select [disabled]="!creationMode" id="template_target" required - name="template_target" title="{{lang.templateTarget}}" - placeholder="{{lang.templateTarget}}" [(ngModel)]="template.template_target" - (ngModelChange)="updateTemplateType()"> - <mat-option value="acknowledgementReceipt">{{lang.acknowledgementReceipt}}</mat-option> - <mat-option value="notes">{{lang.notes}}</mat-option> - <mat-option value="sendmail">{{lang.sendmail}}</mat-option> - <mat-option value="indexingFile">{{lang.indexingFile}}</mat-option> - <mat-option value="notifications">{{lang.notifications}}</mat-option> - <mat-option value="attachments">{{lang.attachments}}</mat-option> + <mat-select [disabled]="!creationMode" name="target" required + title="{{lang.templateTarget}}" placeholder="{{lang.templateTarget}}" + [(ngModel)]="template.target" + (selectionChange)="updateTemplateType($event)"> + <mat-option *ngFor="let target of targetTypes" [value]="target"> + {{lang[target]}}</mat-option> </mat-select> </mat-form-field> </div> </div> - <div class="form-group" *ngIf="template.template_target == 'attachments'"> + <div class="form-group" *ngIf="template.target == 'attachments'"> <div class="col-sm-12"> <mat-form-field> <mat-select id="template_attachment_type" name="template_attachment_type" @@ -85,7 +81,7 @@ </div> </div> - <div class="form-group" *ngIf="template.template_target == 'acknowledgementReceipt'"> + <div class="form-group" *ngIf="template.target == 'acknowledgementReceipt'"> <div class="col-sm-12"> <mat-form-field> <mat-select [disabled]="!creationMode" id="template_attachment_type" @@ -100,48 +96,40 @@ </div> </div> - <div class="form-group" - [hidden]="template.template_target=='attachments' || template.template_target=='notifications' || template.template_target=='doctypes' || template.template_target=='notes' || template.template_target=='acknowledgementReceipt'"> + <div class="form-group" *ngIf="availableTypes.length > 1"> <div class="col-sm-12"> - <mat-radio-group [disabled]="!creationMode" required name="template_type" - [(ngModel)]="template.template_type"> - <mat-radio-button style="margin-left:10px" color="primary" name="template_type" - value="OFFICE" [checked]="template.template_type=='OFFICE'" - *ngIf="template.template_target=='attachments' || template.template_target==''"> - {{lang.office}}</mat-radio-button> - <mat-radio-button style="margin-left:10px" color="primary" name="template_type" - value="HTML" [checked]="template.template_type=='HTML'" - *ngIf="template.template_target=='sendmail' || template.template_target=='doctypes' || template.template_target == 'notifications' || template.template_target == ''" - (click)="initMce('textarea#templateHtml')">{{lang.html}}</mat-radio-button> - <mat-radio-button style="margin-left:10px" color="primary" name="template_type" - value="TXT" [checked]="template.template_type=='TXT'" - *ngIf="template.template_target=='sendmail' || template.template_target=='notes' || template.template_target == ''"> - {{lang.txt}}</mat-radio-button> + <mat-radio-group [disabled]="!creationMode" required name="type" + (change)="changeType($event)"> + <mat-radio-button style="margin-left:10px" color="primary" name="type" + *ngFor="let type of availableTypes" [value]="type" + [checked]="template.type===type"> + {{type}}</mat-radio-button> </mat-radio-group> </div> </div> - <div class="form-group" *ngIf="template.template_type=='OFFICE'"> + <div class="form-group" *ngIf="template.type=='OFFICE'"> <div class="col-md-12" style="display: none;"> <div class="form-inline hide"> <div class="form-group"> - <input type="file" name="files[]" id="uploadSignFileOffice" + <input type="file" name="files[]" #uploadSignFileOffice (change)="uploadFileTrigger($event)" accept="application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml‌.slideshow,application/vnd.oasis.opendocument.text,application/vnd.oasis.opendocument.presentation,application/vnd.oasis.opendocument.spreadsheet"> </div> </div> </div> <div class="col-sm-12"> - <mat-form-field *ngIf="creationMode || template.template_style"> + <mat-form-field *ngIf="creationMode || template.file.name"> <mat-select id="template_style" [disabled]="!creationMode" name="template_style" title="{{lang.defaultTemplate}}" placeholder="{{lang.chosenModel}}" - [(ngModel)]="template.template_style" (ngModelChange)="resetFileUploaded()" - [required]="template.template_target!='acknowledgementReceipt'"> + [(ngModel)]="selectedModelFile" + [required]="template.target!='acknowledgementReceipt'"> <mat-optgroup label="{{lang.loadedFile}} :"> <mat-option class="selectFile" - (click)="clickOnUploader('uploadSignFileOffice')" - value="uploadFile"> + (click)="uploadSignFileOffice.click()" + [value]="template.file.name"> <mat-icon class="fa fa-paperclip" color="primary" - style="height:auto;"></mat-icon> {{buttonFileName}} + style="height:auto;"></mat-icon> + {{!functionsService.empty(template.file) && !functionsService.empty(template.file.name) ? template.file.name : lang.importFile}} </mat-option> </mat-optgroup> <ng-container *ngFor="let extension of extensionModels"> @@ -157,43 +145,45 @@ </mat-select> </mat-form-field> <button mat-raised-button color="default" type="button" - (click)="$event.stopPropagation();startJnlp()" - *ngIf="((creationMode && template.template_style != 'uploadFile' && template.template_style) || (!creationMode))" + (click)="$event.stopPropagation();editFile()" + *ngIf="((creationMode && selectedModelFile) || (!creationMode))" [disabled]="lockFound">{{lang.templateEdition}}</button> <button mat-raised-button color="default" type="button" - (click)="$event.stopPropagation();clickOnUploader('uploadSignFileOffice')" - *ngIf="((creationMode && template.template_style && template.template_style == 'uploadFile') || (!creationMode))" + (click)="$event.stopPropagation();uploadSignFileOffice.click()" + *ngIf="((creationMode && !selectedModelFile) || (!creationMode))" [disabled]="lockFound">{{lang.importFile}}</button> </div> + <iframe *ngIf="templateDocView !== null" [src]="templateDocView" + style="width:100%;height:800px;"></iframe> + <!--<app-document-viewer *ngIf="templateDocView !== null" #appDocumentViewer [editMode]="false" [base64]="templateDocView" style="height:100%;width:100%;"></app-document-viewer>--> </div> - <div class="form-group" *ngIf="template.template_type=='TXT'"> + <div class="form-group" *ngIf="template.type=='TXT'"> <div class="col-sm-12"> <mat-form-field> - <textarea matInput [(ngModel)]="template.template_content" name="templateTxt" + <textarea matInput [(ngModel)]="template.file.content" name="templateTxt" id="templateTxt" placeholder="{{lang.contentTxtTemplate}}" title="{{lang.contentTxtTemplate}}" matTextareaAutosize matAutosizeMinRows="5" matAutosizeMaxRows="5" - [required]="template.template_target!='acknowledgementReceipt'"> + [required]="template.target!='acknowledgementReceipt'"> </textarea> </mat-form-field> </div> </div> - <div class="form-group" *ngIf="template.template_type=='HTML'"> + <div class="form-group" *ngIf="template.type=='HTML'"> <div class="col-sm-12"> <div id="html_mode" style="display: block; width:100%;"> - <textarea [(ngModel)]="template.template_content" name="templateHtml" + <textarea [(ngModel)]="template.file.content" name="templateHtml" id="templateHtml" style="width:100%" rows="15" cols="60" - [required]="template.template_target!='acknowledgementReceipt'"></textarea> + [required]="template.target!='acknowledgementReceipt'"></textarea> </div> </div> </div> - <div class="form-group" *ngIf="template.template_target=='notifications'"> + <div class="form-group" *ngIf="template.target=='notifications'"> <div class="col-sm-12"> <mat-form-field> - <mat-select id="template_datasource" name="template_datasource" + <mat-select id="datasource" name="datasource" title="{{lang.templateDatasource}}" - placeholder="{{lang.templateDatasource}}" - [(ngModel)]="template.template_datasource"> + placeholder="{{lang.templateDatasource}}" [(ngModel)]="template.datasource"> <mat-option value="">{{lang.noDatasource}}</mat-option> <ng-container *ngFor="let datasource of datasourcesList"> <mat-option *ngIf="displayDatasources(datasource)" @@ -204,15 +194,15 @@ </div> </div> - <div class="form-group" *ngIf="template.template_type=='OFFICE_HTML'"> + <div class="form-group" *ngIf="template.type=='OFFICE_HTML'"> <mat-tab-group (selectedTabChange)="loadTab($event);"> <mat-tab label="{{lang.electronicTemplate}}"> <div class="col-sm-12"> <div id="html_mode" style="display: block; width:100%;"> - <textarea [(ngModel)]="template.template_content" + <textarea [(ngModel)]="template.file.electronic.content" name="templateOfficeHtml" id="templateOfficeHtml" style="width:100%" rows="15" cols="60" - [required]="template.template_target!='acknowledgementReceipt'"></textarea> + [required]="template.target!='acknowledgementReceipt'"></textarea> </div> </div> </mat-tab> @@ -220,7 +210,7 @@ <div class="col-md-12" style="display: none;"> <div class="form-inline hide"> <div class="form-group"> - <input type="file" name="files[]" id="uploadSignFileOfficeHtml" + <input type="file" name="files[]" #uploadSignFileOfficeHtml (change)="uploadFileTrigger($event)" accept="application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml‌.slideshow,application/vnd.oasis.opendocument.text,application/vnd.oasis.opendocument.presentation,application/vnd.oasis.opendocument.spreadsheet"> </div> @@ -229,18 +219,18 @@ <div class="col-sm-12"> <mat-form-field> <mat-select id="template_style" - [disabled]="!creationMode && template.template_file_name != null" + [disabled]="!creationMode && template.file.paper.name !== null" name="template_style" title="{{lang.defaultTemplate}}" placeholder="{{lang.chosenModel}}" - [(ngModel)]="template.template_style" + [(ngModel)]="selectedModelFile" (ngModelChange)="resetFileUploaded()" - [required]="template.template_target!='acknowledgementReceipt'"> + [required]="template.target!='acknowledgementReceipt'"> <mat-optgroup label="{{lang.loadedFile}} :"> <mat-option - (click)="clickOnUploader('uploadSignFileOfficeHtml')" - style="text-align: center;" value="uploadFile"> + (click)="uploadSignFileOfficeHtml.click()" + style="text-align: center;" [value]="template.file.paper.name"> <mat-icon class="fa fa-paperclip" color="primary" - style="height:auto;"></mat-icon> {{buttonFileName}} + style="height:auto;"></mat-icon> {{!functionsService.empty(template.file.paper) && !functionsService.empty(template.file.paper.name) ? template.file.paper.name : lang.importFile}} </mat-option> </mat-optgroup> <ng-container *ngFor="let extension of extensionModels"> @@ -256,14 +246,16 @@ </mat-select> </mat-form-field> <button mat-raised-button color="default" type="button" - (click)="$event.stopPropagation();startJnlp()" - *ngIf="template.template_file_name != null || (template.template_style != 'uploadFile' && template.template_style)" + (click)="$event.stopPropagation();editFile()" + *ngIf="((creationMode && selectedModelFile) || (!creationMode))" [disabled]="lockFound">{{lang.templateEdition}}</button> <button mat-raised-button color="default" type="button" - (click)="$event.stopPropagation();clickOnUploader('uploadSignFileOfficeHtml')" - *ngIf="template.template_file_name != null || (template.template_style && template.template_style == 'uploadFile')" + (click)="$event.stopPropagation();uploadSignFileOfficeHtml.click()" + *ngIf="!selectedModelFile || !creationMode" [disabled]="lockFound">{{lang.importFile}}</button> </div> + <iframe *ngIf="templateDocView !== null" [src]="templateDocView" + style="width:100%;height:800px;"></iframe> </mat-tab> </mat-tab-group> </div> @@ -293,4 +285,4 @@ </div> </mat-list> </mat-sidenav> -</mat-sidenav-container> +</mat-sidenav-container> \ No newline at end of file diff --git a/src/frontend/app/administration/template/template-administration.component.ts b/src/frontend/app/administration/template/template-administration.component.ts index 16bdf237f7c..d1fcad0c671 100755 --- a/src/frontend/app/administration/template/template-administration.component.ts +++ b/src/frontend/app/administration/template/template-administration.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, NgZone, ViewChild, Inject, TemplateRef, ViewContainerRef } from '@angular/core'; +import { Component, OnInit, ViewChild, Inject, TemplateRef, ViewContainerRef } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Router, ActivatedRoute } from '@angular/router'; import { LANG } from '../../translate.component'; @@ -7,6 +7,12 @@ import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dial import { MatSidenav } from '@angular/material/sidenav'; import { HeaderService } from '../../../service/header.service'; import { AppService } from '../../../service/app.service'; +import { filter, tap, catchError } from 'rxjs/operators'; +import { FunctionsService } from '../../../service/functions.service'; +import { of } from 'rxjs/internal/observable/of'; +import { TemplateFileEditorModalComponent } from './templateFileEditorModal/template-file-editor-modal.component'; +import { DomSanitizer } from '@angular/platform-browser'; +import { AlertComponent } from '../../../plugins/modal/alert.component'; declare var tinymce: any; @@ -24,7 +30,45 @@ export class TemplateAdministrationComponent implements OnInit { loading: boolean = false; creationMode: boolean; - template: any = {}; + + template: any = { + label: '', + description: '', + datasource: 'letterbox_attachment', + target: '', + type: '', + file: null + }; + + targetTypes: string[] = [ + 'acknowledgementReceipt', + 'notes', + 'sendmail', + 'indexingFile', + 'notifications', + 'attachments' + ]; + + allowedExtensions: string[] = [ + 'doc', + 'docx', + 'dotx', + 'odt', + 'ott', + 'rtf', + 'txt', + 'html', + 'xlsl', + 'xlsx', + 'xltx', + 'ods', + 'ots', + 'csv', + ]; + + selectedModelFile: any = null; + availableTypes: string[] = []; + statuses: any[] = []; categoriesList: any[] = []; keywordsList: any[] = []; @@ -37,6 +81,8 @@ export class TemplateAdministrationComponent implements OnInit { lockFound: boolean = false; intervalLockFile: any; + templateDocView: any = null; + dialogRef: MatDialogRef<any>; data: any[] = []; config: any = {}; @@ -44,19 +90,16 @@ export class TemplateAdministrationComponent implements OnInit { constructor( public http: HttpClient, - private zone: NgZone, + private sanitizer: DomSanitizer, private route: ActivatedRoute, private router: Router, private notify: NotificationService, private headerService: HeaderService, public dialog: MatDialog, public appService: AppService, - private viewContainerRef: ViewContainerRef - ) { - window['angularTemplateComponent'] = { - componentAfterUpload: (base64Content: any) => this.processAfterUpload(base64Content) - }; - } + private viewContainerRef: ViewContainerRef, + private functionsService: FunctionsService + ) { } ngOnInit(): void { this.loading = true; @@ -71,8 +114,6 @@ export class TemplateAdministrationComponent implements OnInit { this.http.get('../../rest/administration/templates/new') .subscribe((data: any) => { this.setInitialValue(data); - this.template.template_target = ''; - this.template.template_type = 'OFFICE'; this.loading = false; }); @@ -82,24 +123,36 @@ export class TemplateAdministrationComponent implements OnInit { this.http.get('../../rest/templates/' + params['id'] + '/details') .subscribe((data: any) => { this.setInitialValue(data); - this.template = data.template; + this.template = { + label: data.template.template_label, + description: data.template.template_comment, + datasource: data.template.template_datasource, + target: data.template.template_target, + type: data.template.template_type, + file: {} + }; + this.updateTemplateType(); + + this.selectedModelFile = data.template.template_file_name; + if (this.template.type === 'HTML' || this.template.type === 'TXT') { + this.template.file.content = data.template.template_content; + } else if (this.template.type === 'OFFICE') { + this.template.file.format = data.template.template_file_name.split('.').pop(); + this.template.file.name = data.template.template_file_name; + } else if (this.template.target === 'acknowledgementReceipt') { + this.template.file.paper.format = data.template.template_file_name.split('.').pop(); + this.template.file.paper.name = data.template.template_file_name; + this.template.file.electronic.content = data.template.template_content; + this.template.template_attachment_type = data.template.template_attachment_type; + } + this.headerService.setHeader(this.lang.templateModification, this.template.template_label); this.loading = false; - if (this.template.template_type === 'HTML') { - this.initMce('textarea#templateHtml'); - } - if (this.template.template_type === 'OFFICE_HTML') { - this.initMce('textarea#templateOfficeHtml'); - } - if (this.template.template_style === '' && this.template.template_file_name != null) { - this.buttonFileName = this.template.template_file_name; - } else if (this.template.template_style !== '') { - this.buttonFileName = this.template.template_style; - } - if (this.template.template_style === '') { - this.template.template_style = 'uploadFile'; - } + console.log(this.selectedModelFile); + console.log(this.template); + console.log(data); + }); } if (!this.template.template_attachment_type) { @@ -121,7 +174,6 @@ export class TemplateAdministrationComponent implements OnInit { language_url: `../../node_modules/tinymce-i18n/langs/${this.lang.langISO.replace('-', '_')}.js`, height: '200', plugins: [ - 'textcolor', 'autoresize', 'code' ], @@ -140,11 +192,11 @@ export class TemplateAdministrationComponent implements OnInit { theme_styles: 'Header 1=header1;Header 2=header2;Header 3=header3;Table Row=tableRow1', setup: (ed: any) => { ed.on('keyup', (e: any) => { - if (this.template.template_type === 'HTML' && tinymce.get('templateHtml') != null) { - this.template.template_content = tinymce.get('templateHtml').getContent(); + if (this.template.type === 'HTML' && tinymce.get('templateHtml') != null) { + this.template.file.content = tinymce.get('templateHtml').getContent(); } - if (this.template.template_type === 'OFFICE_HTML' && tinymce.get('templateOfficeHtml') != null) { - this.template.template_content = tinymce.get('templateOfficeHtml').getContent(); + if (this.template.type === 'OFFICE_HTML' && tinymce.get('templateOfficeHtml') != null) { + this.template.file.electronic.content = tinymce.get('templateOfficeHtml').getContent(); } }); } @@ -194,81 +246,189 @@ export class TemplateAdministrationComponent implements OnInit { }, 0); } - clickOnUploader(id: string) { - $('#' + id).click(); + getBase64Document(buffer: ArrayBuffer) { + const TYPED_ARRAY = new Uint8Array(buffer); + const STRING_CHAR = TYPED_ARRAY.reduce((data, byte) => { + return data + String.fromCharCode(byte); + }, ''); + + return btoa(STRING_CHAR); } uploadFileTrigger(fileInput: any) { - this.template.jnlpUniqueId = null; - if (fileInput.target.files && fileInput.target.files[0]) { - this.template.uploadedFile = {}; - this.template.uploadedFile.name = fileInput.target.files[0].name; - this.template.uploadedFile.size = fileInput.target.files[0].size; - this.template.uploadedFile.type = fileInput.target.files[0].type; - if (this.template.uploadedFile.label === '') { - this.template.uploadedFile.label = this.template.uploadedFile.name; - } + if (fileInput.target.files && fileInput.target.files[0] && this.isExtensionAllowed(fileInput.target.files[0])) { const reader = new FileReader(); - reader.readAsDataURL(fileInput.target.files[0]); - reader.onload = function (value: any) { - window['angularTemplateComponent'].componentAfterUpload(value.target.result); + if (this.template.target === 'acknowledgementReceipt') { + this.template.file.paper = { + name: '', + type: '', + content: '' + }; + this.template.file.paper.name = fileInput.target.files[0].name; + this.selectedModelFile = this.template.file.paper.name; + this.template.file.paper.type = fileInput.target.files[0].type; + this.template.file.paper.format = this.template.file.paper.name.split('.').pop(); + } else { + this.template.file = { + name: '', + type: '', + content: '' + }; + this.template.file.name = fileInput.target.files[0].name; + this.selectedModelFile = this.template.file.name; + this.template.file.type = fileInput.target.files[0].type; + this.template.file.format = this.template.file.name.split('.').pop(); + } + + reader.readAsArrayBuffer(fileInput.target.files[0]); + + reader.onload = (value: any) => { + if (this.template.target === 'acknowledgementReceipt') { + this.template.file.paper.content = this.getBase64Document(value.target.result); + } else { + this.template.file.content = this.getBase64Document(value.target.result); + } + + this.getViewTemplateFile(); }; } } - processAfterUpload(b64Content: any) { - this.zone.run(() => this.resfreshUpload(b64Content)); - } + isExtensionAllowed(file: any) { + const fileExtension = file.name.toLowerCase().split('.').pop(); - resfreshUpload(b64Content: any) { - this.template.uploadedFile.base64 = b64Content.replace(/^data:.*?;base64,/, ''); - this.template.template_style = 'uploadFile'; - this.fileImported(); + if (this.allowedExtensions.filter(ext => ext.toLowerCase() === fileExtension.toLowerCase()).length === 0) { + this.dialog.open(AlertComponent, { panelClass: 'maarch-modal', autoFocus: false, disableClose: true, data: { title: this.lang.notAllowedExtension + ' !', msg: this.lang.file + ' : <b>' + file.name + '</b>, ' + this.lang.type + ' : <b>' + file.type + '</b><br/><br/><u>' + this.lang.allowedExtensions + '</u> : <br/>' + this.allowedExtensions.filter((elem: any, index: any, self: any) => index === self.indexOf(elem)).join(', ') } }); + return false; + } else { + return true; + } } - startJnlp() { - if (this.creationMode || (this.template.template_file_name == null && this.template.template_path == null)) { - this.jnlpValue.objectType = 'templateCreation'; + editFile() { + const editorOptions: any = {}; + + if (this.creationMode || ((this.template.target !== 'acknowledgementReceipt' && this.functionsService.empty(this.template.file.name) || (this.template.target === 'acknowledgementReceipt' && this.functionsService.empty(this.template.file.paper.name))))) { for (const element of this.defaultTemplatesList) { - if (this.template.template_style === element.fileExt + ': ' + element.fileName) { - this.jnlpValue.objectId = element.filePath; + if (this.selectedModelFile === element.fileExt + ': ' + element.fileName) { + editorOptions.objectId = element.filePath; } } + editorOptions.objectType = 'templateCreation'; + editorOptions.docUrl = `rest/onlyOffice/mergedFile`; + editorOptions.extension = editorOptions.objectId.toLowerCase().split('.').pop(); + } else { - this.jnlpValue.objectType = 'templateModification'; - this.jnlpValue.objectId = this.template.template_id; + editorOptions.objectType = 'templateModification'; + editorOptions.objectId = this.template.template_id; + editorOptions.extension = this.template.target === 'acknowledgementReceipt' ? this.template.file.paper.name : this.template.file.name; + } + + if (this.headerService.user.preferences.documentEdition === 'java') { + this.launchJavaEditor(editorOptions); + } else if (this.headerService.user.preferences.documentEdition === 'onlyoffice') { + this.launchOOEditor(editorOptions); } - this.jnlpValue.table = 'templates'; - this.jnlpValue.uniqueId = 0; - this.jnlpValue.cookies = document.cookie; - - this.http.post('../../rest/jnlp', this.jnlpValue) - .subscribe((data: any) => { - this.template.jnlpUniqueId = data.jnlpUniqueId; - this.fileToImport(); + } + + launchJavaEditor(params: any) { + this.http.post('../../rest/jnlp', params).pipe( + tap((data: any) => { window.location.href = '../../rest/jnlp/' + data.generatedJnlp; - this.checkLockFile(); - }, (err) => { - this.notify.error(err.error.errors); - }); + this.checkLockFile(data.jnlpUniqueId, params.extension); + }), + catchError((err: any) => { + this.notify.handleSoftErrors(err); + return of(false); + }) + ).subscribe(); + } + + launchOOEditor(params: any) { + this.dialogRef = this.dialog.open( + TemplateFileEditorModalComponent, + { + autoFocus: false, + panelClass: 'maarch-full-height-modal', + minWidth: '80%', + disableClose: true, + data: { + title: this.template.template_style, + editorOptions: params, + file: { format: params.extension } + } + } + ); + this.dialogRef.afterClosed().pipe( + filter((data: string) => !this.functionsService.empty(data)), + tap((data: any) => { + if (this.template.target === 'acknowledgementReceipt') { + this.template.file.paper.name = this.selectedModelFile; + this.template.file.paper.format = params.extension; + this.template.file.paper.content = data.content; + } else { + this.template.file.name = this.selectedModelFile; + this.template.file.format = params.extension; + this.template.file.content = data.content; + } + this.getViewTemplateFile(); + }), + catchError((err: any) => { + this.notify.handleErrors(err); + return of(false); + }) + ).subscribe(); + } + + getViewTemplateFile() { + + this.http.post('../../rest/convertedFile/encodedFile', { encodedFile: this.template.target === 'acknowledgementReceipt' ? this.template.file.paper.content : this.template.file.content, format: this.template.target === 'acknowledgementReceipt' ? this.template.file.paper.format : this.template.file.format }).pipe( + tap((data: any) => { + this.templateDocView = this.sanitizer.bypassSecurityTrustResourceUrl('data:application/pdf;base64,' + data.encodedResource); + }), + catchError((err: any) => { + this.notify.handleSoftErrors(err); + return of(false); + }) + ).subscribe(); + } - checkLockFile() { + checkLockFile(id: string, extension: string) { this.intervalLockFile = setInterval(() => { - this.http.get('../../rest/jnlp/lock/' + this.template.jnlpUniqueId) - .subscribe((data: any) => { + this.http.get('../../rest/jnlp/lock/' + id).pipe( + tap((data: any) => { this.lockFound = data.lockFileFound; if (!this.lockFound) { clearInterval(this.intervalLockFile); + this.loadTmpFile(`${data.fileTrunk}.${extension}`); } - }); + }) + ).subscribe(); }, 1000); } + loadTmpFile(filenameOnTmp: string) { + this.http.get(`../../rest/convertedFile/${filenameOnTmp}?convert=true`).pipe( + tap((data: any) => { + if (this.template.target === 'acknowledgementReceipt') { + this.template.file.paper.name = this.selectedModelFile; + this.template.file.paper.format = filenameOnTmp.toLowerCase().split('.').pop(); + this.template.file.paper.content = data.encodedResource; + } else { + this.template.file.name = this.selectedModelFile; + this.template.file.format = filenameOnTmp.toLowerCase().split('.').pop(); + this.template.file.content = data.encodedResource; + } + this.templateDocView = data.encodedConvertedResource; + }) + ).subscribe(); + } + duplicateTemplate() { - if (!this.lockFound && this.template.template_target !== 'acknowledgementReceipt') { + if (!this.lockFound && this.template.target !== 'acknowledgementReceipt') { const r = confirm(this.lang.confirmDuplicate); if (r) { @@ -284,127 +444,143 @@ export class TemplateAdministrationComponent implements OnInit { } onSubmit() { - this.template.entities = $('#jstree').jstree(true).get_checked([true]); - if (this.template.template_target !== 'notifications') { - this.template.template_datasource = 'letterbox_attachment'; - } + this.formatTemplate(); - if (this.template.template_type === 'HTML') { + /*this.template.entities = $('#jstree').jstree(true).get_checked([true]); + if (this.template.type === 'HTML') { this.template.template_content = tinymce.get('templateHtml').getContent(); - } else if (this.template.template_type === 'OFFICE_HTML') { + } else if (this.template.type === 'OFFICE_HTML') { this.template.template_content = tinymce.get('templateOfficeHtml').getContent(); + }*/ + + if (this.isValidTemplate()) { + if (this.creationMode) { + this.http.post('../../rest/templates', this.template) + .subscribe((data: any) => { + if (data.checkEntities) { + this.config = { + panelClass: 'maarch-modal', + data: { + entitiesList: data.checkEntities, + template_attachment_type: this.template.template_attachment_type + } + }; + this.dialog.open(TemplateAdministrationCheckEntitiesModalComponent, this.config); + } else { + this.router.navigate(['/administration/templates']); + this.notify.success(this.lang.templateAdded); + } + }, (err) => { + this.notify.error(err.error.errors); + }); + } else { + this.http.put('../../rest/templates/' + this.template.template_id, this.template) + .subscribe((data: any) => { + if (data.checkEntities) { + this.config = { + panelClass: 'maarch-modal', + data: { + entitiesList: data.checkEntities, + template_attachment_type: this.template.template_attachment_type + } + }; + this.dialogRef = this.dialog.open(TemplateAdministrationCheckEntitiesModalComponent, this.config); + } else { + this.router.navigate(['/administration/templates']); + this.notify.success(this.lang.templateUpdated); + } + }, (err) => { + this.notify.error(err.error.errors); + }); + } } - if (this.template.template_target === 'acknowledgementReceipt') { - if (this.template.template_content === '' && (!this.template.template_style || (this.template.template_style && !this.template.jnlpUniqueId && !this.template.uploadedFile && !this.template.template_file_name))) { + } + + formatTemplate() { + const template = { ...this.template }; + console.log(template); + + } + + isValidTemplate() { + if (this.template.target === 'acknowledgementReceipt') { + if (this.functionsService.empty(this.template.file.paper.name) && this.functionsService.empty(this.template.file.electronic.content)) { alert(this.lang.mustCompleteAR); - return; + return false; } - } else if (this.template.template_target !== 'acknowledgementReceipt' && this.template.template_type === 'OFFICE') { - if (!this.template.template_style || (this.template.template_style && !this.template.jnlpUniqueId && !this.template.template_file_name && !this.template.uploadedFile)) { + } else if (this.template.target !== 'acknowledgementReceipt' && this.template.type === 'OFFICE') { + if (this.functionsService.empty(this.template.file.name)) { alert(this.lang.editModelFirst); - return; + return false; } - } - - if (this.creationMode) { - if (this.template.template_style === 'uploadFile') { - this.template.template_style = ''; - } - this.http.post('../../rest/templates', this.template) - .subscribe((data: any) => { - if (data.checkEntities) { - this.config = { - panelClass: 'maarch-modal', - data: { - entitiesList: data.checkEntities, - template_attachment_type: this.template.template_attachment_type - } - }; - this.dialogRef = this.dialog.open(TemplateAdministrationCheckEntitiesModalComponent, this.config); - } else { - this.router.navigate(['/administration/templates']); - this.notify.success(this.lang.templateAdded); - } - }, (err) => { - this.notify.error(err.error.errors); - }); } else { - if (this.template.template_style === 'uploadFile') { - this.template.template_style = ''; - } - this.http.put('../../rest/templates/' + this.template.template_id, this.template) - .subscribe((data: any) => { - if (data.checkEntities) { - this.config = { - panelClass: 'maarch-modal', - data: { - entitiesList: data.checkEntities, - template_attachment_type: this.template.template_attachment_type - } - }; - this.dialogRef = this.dialog.open(TemplateAdministrationCheckEntitiesModalComponent, this.config); - } else { - this.router.navigate(['/administration/templates']); - this.notify.success(this.lang.templateUpdated); - } - }, (err) => { - this.notify.error(err.error.errors); - }); - } - } - - checkArMode() { - if (this.template.template_content === '' && !this.template.template_style && this.template.target === 'acknowledgementReceipt') { - alert(this.lang.mustCompleteAR); return true; - } else { - return false; } } displayDatasources(datasource: any) { - if (datasource.target === 'notification' && this.template.template_target === 'notifications') { + if (datasource.target === 'notification' && this.template.target === 'notifications') { return true; - } else if (datasource.target === 'document' && this.template.template_target !== 'notifications') { + } else if (datasource.target === 'document' && this.template.target !== 'notifications') { return true; } return false; } updateTemplateType() { - if (this.template.template_target === 'attachments' || this.template.template_target === 'indexingFile') { - this.template.template_type = 'OFFICE'; - } else if (this.template.template_target === 'notifications' || this.template.template_target === 'doctypes' || this.template.template_target === 'sendmail') { - this.template.template_type = 'HTML'; + this.template.file = { + name: '', + type: '', + content: '' + }; + + this.templateDocView = null; + if (['attachments', 'indexingFile'].indexOf(this.template.target) > -1) { + this.template.type = 'OFFICE'; + this.availableTypes = ['OFFICE']; + } else if (['notifications', 'sendmail'].indexOf(this.template.target) > -1) { + this.template.type = 'HTML'; + this.availableTypes = ['HTML', 'TXT']; this.initMce('textarea#templateHtml'); - } else if (this.template.template_target === 'notes') { - this.template.template_type = 'TXT'; - } else if (this.template.template_target === 'acknowledgementReceipt') { - this.template.template_type = 'OFFICE_HTML'; + } else if (this.template.target === 'notes') { + this.template.type = 'TXT'; + this.availableTypes = ['TXT']; + } else if (this.template.target === 'acknowledgementReceipt') { + this.template.file = { + electronic: { + name: '', + type: '', + content: '' + }, + paper: { + name: '', + type: '', + content: '' + } + }; + this.template.type = 'OFFICE_HTML'; + this.availableTypes = []; this.template.template_attachment_type = ''; this.initMce('textarea#templateOfficeHtml'); } } - fileImported() { - this.buttonFileName = this.template.uploadedFile.name; - } - - fileToImport() { - this.buttonFileName = this.lang.importFile; - } - - resetFileUploaded() { - this.fileToImport(); - this.template.uploadedFile = null; + changeType(ev: any) { + if (ev.value === 'HTML') { + this.initMce('textarea#templateHtml'); + } else { + tinymce.remove('textarea'); + } + this.template.type = ev.value; } loadTab(event: any) { if (event.index === 0) { this.initMce('textarea#templateOfficeHtml'); } else { + tinymce.remove('textarea'); if (this.template.template_file_name == null && this.template.template_style == null) { this.buttonFileName = this.lang.importFile; } diff --git a/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.html b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.html new file mode 100644 index 00000000000..0d2a71e8664 --- /dev/null +++ b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.html @@ -0,0 +1,13 @@ +<div class="mat-dialog-content-container"> + <mat-dialog-content style="padding: 0px;"> + <onlyoffice-viewer #onlyofficeViewer style="height:100%;width:100%;" [hideCloseEditor]="true" + [params]="editorOptions" [file]="file" [editMode]="true" (triggerAfterUpdatedDoc)="close()" + (triggerCloseEditor)="dialogRef.close('');" (triggerModifiedDocument)="isDocModified = true"></onlyoffice-viewer> + </mat-dialog-content> + <span class="divider-modal"></span> + <div mat-dialog-actions class="actions"> + <button mat-raised-button mat-button color="primary" + (click)="close()">{{lang.validate}}</button> + <button mat-raised-button mat-button [disabled]="loading" [mat-dialog-close]="">{{lang.cancel}}</button> + </div> +</div> \ No newline at end of file diff --git a/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.scss b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.ts b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.ts new file mode 100644 index 00000000000..04da26ed67a --- /dev/null +++ b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.ts @@ -0,0 +1,36 @@ +import { Component, OnInit, Inject, ViewChild } from '@angular/core'; +import { LANG } from '../../../translate.component'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { take } from 'rxjs/internal/operators/take'; +import { tap } from 'rxjs/internal/operators/tap'; +import { EcplOnlyofficeViewerComponent } from '../../../../plugins/onlyoffice-api-js/onlyoffice-viewer.component'; + +@Component({ + templateUrl: 'template-file-editor-modal.component.html', + styleUrls: ['template-file-editor-modal.component.scss'], +}) +export class TemplateFileEditorModalComponent implements OnInit { + + lang: any = LANG; + loading: boolean = false; + editorOptions: any = null; + file: any = null; + + @ViewChild('onlyofficeViewer', { static: true }) onlyofficeViewer: EcplOnlyofficeViewerComponent; + + constructor(public dialogRef: MatDialogRef<TemplateFileEditorModalComponent>, @Inject(MAT_DIALOG_DATA) public data: any) { } + + ngOnInit(): void { + this.editorOptions = this.data.editorOptions; + this.file = this.data.file; + } + + close() { + this.onlyofficeViewer.getFile().pipe( + take(1), + tap((data: any) => { + this.dialogRef.close(data); + }) + ).subscribe(); + } +} diff --git a/src/frontend/app/viewer/document-viewer.component.ts b/src/frontend/app/viewer/document-viewer.component.ts index fac3cc4160e..f6eb6e4aab5 100755 --- a/src/frontend/app/viewer/document-viewer.component.ts +++ b/src/frontend/app/viewer/document-viewer.component.ts @@ -155,7 +155,7 @@ export class DocumentViewerComponent implements OnInit { extension: '.' + ext.extension.toLowerCase(), mimeType: ext.mimeType, canConvert: ext.canConvert - } + }; }); this.allowedExtensions = this.sortPipe.transform(this.allowedExtensions, 'extension'); @@ -184,7 +184,7 @@ export class DocumentViewerComponent implements OnInit { if (!this.functions.empty(this.base64)) { this.loadFileFromBase64(); - } else if (this.tmpFilename != '' && this.tmpFilename !== undefined) { + } else if (this.tmpFilename !== '' && this.tmpFilename !== undefined) { this.http.get('../../rest/convertedFile/' + this.tmpFilename).pipe( tap((data: any) => { this.file = { diff --git a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.html b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.html index 3a8a765375b..a2545c0bc0e 100644 --- a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.html +++ b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.html @@ -1,5 +1,5 @@ <div *ngIf="loading" style="display:block;padding: 10px;">{{lang.checkOnlyofficeServer}}...</div> -<button class="onlyofficeButton_fullscreen" [class.fullScreen]="fullscreenMode" mat-mini-fab color="warn" +<button *ngIf="!hideCloseEditor" class="onlyofficeButton_fullscreen" [class.fullScreen]="fullscreenMode" mat-mini-fab color="warn" [title]="lang.closeEditor" (click)="quit()"> <mat-icon class="fa fa-times" style="height:auto;"></mat-icon> </button> diff --git a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts index bb547e5a0a5..ee19865cadf 100644 --- a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts +++ b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts @@ -10,7 +10,7 @@ import { } from '@angular/core'; import './onlyoffice-api.js'; import { HttpClient } from '@angular/common/http'; -import { catchError, tap, filter } from 'rxjs/operators'; +import { catchError, tap, filter, finalize } from 'rxjs/operators'; import { LANG } from '../../app/translate.component'; import { ConfirmComponent } from '../modal/confirm.component'; import { MatDialogRef, MatDialog } from '@angular/material/dialog'; @@ -36,6 +36,7 @@ export class EcplOnlyofficeViewerComponent implements OnInit, AfterViewInit, OnD @Input() editMode: boolean = false; @Input() file: any = {}; @Input() params: any = {}; + @Input() hideCloseEditor: any = false; @Output() triggerAfterUpdatedDoc = new EventEmitter<string>(); @Output() triggerCloseEditor = new EventEmitter<string>(); @@ -62,7 +63,13 @@ export class EcplOnlyofficeViewerComponent implements OnInit, AfterViewInit, OnD 'ott', 'rtf', 'txt', - 'html' + 'html', + 'xlsl', + 'xlsx', + 'xltx', + 'ods', + 'ots', + 'csv', ]; private eventAction = new Subject<any>(); @@ -227,7 +234,7 @@ export class EcplOnlyofficeViewerComponent implements OnInit, AfterViewInit, OnD }), catchError((err) => { this.notify.handleErrors(err); - this.closeEditor(); + this.triggerCloseEditor.emit(); return of(false); }), ).subscribe(); diff --git a/src/frontend/service/auth-interceptor.service.ts b/src/frontend/service/auth-interceptor.service.ts index 89d37194357..a5982031f67 100644 --- a/src/frontend/service/auth-interceptor.service.ts +++ b/src/frontend/service/auth-interceptor.service.ts @@ -93,7 +93,7 @@ export class AuthInterceptor implements HttpInterceptor { }) ); } else { - return of(false); + return next.handle(request); } }) ); -- GitLab