diff --git a/rest/index.php b/rest/index.php
index d5becdaeb76c16d8fa9d93f2d542634a03534011..cfd934219a330a346afcc19e3d7b73997b27c161 100755
--- a/rest/index.php
+++ b/rest/index.php
@@ -25,7 +25,6 @@ if (file_exists("custom/{$customId}/src/core/lang/lang-{$language}.php")) {
 }
 require_once("src/core/lang/lang-{$language}.php");
 
-
 $app = new \Slim\App(['settings' => ['displayErrorDetails' => true, 'determineRouteBeforeAppMiddleware' => true, 'addContentLengthHeader' => true ]]);
 
 //Authentication
@@ -34,8 +33,7 @@ $app->add(function (\Slim\Http\Request $request, \Slim\Http\Response $response,
     $route = $request->getAttribute('route');
     $currentMethod = empty($route) ? '' : $route->getMethods()[0];
     $currentRoute = empty($route) ? '' : $route->getPattern();
-
-    if (!in_array($currentMethod.$currentRoute, $routesWithoutAuthentication)) {
+    if (!in_array($currentMethod.$currentRoute, $routesWithoutAuthentication) && preg_match('/POST\/test*/', $currentMethod.$currentRoute) == 0) {
         $login = \SrcCore\controllers\AuthenticationController::authentication();
         if (!empty($login)) {
             \SrcCore\controllers\CoreController::setGlobals(['login' => $login]);
@@ -258,6 +256,7 @@ $app->put('/indexingModels/{id}/enable', \IndexingModel\controllers\IndexingMode
 $app->delete('/indexingModels/{id}', \IndexingModel\controllers\IndexingModelController::class . ':delete');
 
 //Jnlp
+$app->post('/test', \ContentManagement\controllers\JnlpController::class . ':test');
 $app->post('/jnlp', \ContentManagement\controllers\JnlpController::class . ':generateJnlp');
 $app->get('/jnlp/{jnlpUniqueId}', \ContentManagement\controllers\JnlpController::class . ':renderJnlp');
 $app->post('/jnlp/{jnlpUniqueId}', \ContentManagement\controllers\JnlpController::class . ':processJnlp');
diff --git a/src/app/contentManagement/controllers/JnlpController.php b/src/app/contentManagement/controllers/JnlpController.php
index e89147ca78014ec200111743049c2abdad0305e0..3e414e33d27fb45862683df4cdd71b661b05dea7 100755
--- a/src/app/contentManagement/controllers/JnlpController.php
+++ b/src/app/contentManagement/controllers/JnlpController.php
@@ -36,7 +36,7 @@ class JnlpController
         $jnlpFileNameExt = $jnlpFileName . '.jnlp';
 
         $allCookies = '';
-        foreach($_COOKIE as $key => $value) {
+        foreach ($_COOKIE as $key => $value) {
             if (!empty($allCookies)) {
                 $allCookies .= '; ';
             }
@@ -380,4 +380,25 @@ class JnlpController
 
         return $response->saveXML();
     }
+
+    public static function test(Request $request, Response $response)
+    {
+        if (($body_stream = file_get_contents("php://input"))===false) {
+            echo "Bad Request";
+        }
+        
+        $data = json_decode($body_stream, true);
+        
+        if ($data["status"] == 2) {
+            $downloadUri = $data["url"];
+                
+            if (($new_data = file_get_contents($downloadUri))===false) {
+                echo "Bad Response";
+            } else {
+                echo $new_data;
+                //file_put_contents($path_for_save, $new_data, LOCK_EX);
+            }
+        }
+        return $response->withJson(['error' => 0]);
+    }
 }
diff --git a/src/frontend/app/app-common.module.ts b/src/frontend/app/app-common.module.ts
index 8cd927b0f0dc9c7ea80ab76212c39771f24aab3a..e146cac93b0a75acb6a953a4383e33aebce4f479 100755
--- a/src/frontend/app/app-common.module.ts
+++ b/src/frontend/app/app-common.module.ts
@@ -21,6 +21,7 @@ import { TimeAgoPipe }                          from '../plugins/timeAgo.pipe';
 import { TimeLimitPipe }                        from '../plugins/timeLimit.pipe';
 import { FilterListPipe }                       from '../plugins/filterList.pipe';
 import { FullDatePipe }                       from '../plugins/fullDate.pipe';
+import { EcplOnlyofficeViewerComponent }                       from '../plugins/onlyoffice-api-js/onlyoffice-viewer.component';
 
 /*FRONT IMPORTS*/
 import { AppMaterialModule }                    from './app-material.module';
@@ -116,7 +117,8 @@ export class MyHammerConfig extends HammerGestureConfig {
         TagInputComponent,
         DiffusionsListComponent,
         DocumentViewerComponent,
-        DragDropDirective
+        DragDropDirective,
+        EcplOnlyofficeViewerComponent
     ],
     exports: [
         CommonModule,
@@ -155,7 +157,8 @@ export class MyHammerConfig extends HammerGestureConfig {
         TagInputComponent,
         DiffusionsListComponent,
         DocumentViewerComponent,
-        DragDropDirective
+        DragDropDirective,
+        EcplOnlyofficeViewerComponent
     ],
     providers: [
         HeaderService,
diff --git a/src/frontend/app/attachments/attachments-page/attachment-page.component.html b/src/frontend/app/attachments/attachments-page/attachment-page.component.html
index 4326ef9251e8d710f39406c0ec10b9a342e7fb07..6994e2acd4a0e0e94c5af5ad7535eb511896138a 100644
--- a/src/frontend/app/attachments/attachments-page/attachment-page.component.html
+++ b/src/frontend/app/attachments/attachments-page/attachment-page.component.html
@@ -223,7 +223,7 @@
     </mat-dialog-content>
     <div mat-dialog-actions class="actions">
         <button mat-raised-button color="primary" *ngIf="!newVersion" (click)="updateAttachment()"
-            [disabled]="!loading && (!editMode || !attachFormGroup.valid)">{{lang.update}}</button>
+            [disabled]="!loading && (!editMode || !attachFormGroup.valid)">{{lang.validate}}</button>
         <button mat-raised-button color="primary" *ngIf="newVersion" (click)="createNewVersion()"
             [disabled]="!editMode || attachment['encodedFile'].value === null">{{lang.createNewVersion}}</button>
         <button mat-raised-button color="warn" *ngIf=" !loading && attachment.status.value === 'SIGN'"
diff --git a/src/frontend/app/attachments/attachments-page/attachment-page.component.ts b/src/frontend/app/attachments/attachments-page/attachment-page.component.ts
index cd4736b45b5a4d179c7a92e67cd3ffb66146d8f4..93b86ff96c65804064bd68a2f784287f3a5f0d24 100644
--- a/src/frontend/app/attachments/attachments-page/attachment-page.component.ts
+++ b/src/frontend/app/attachments/attachments-page/attachment-page.component.ts
@@ -97,7 +97,7 @@ export class AttachmentPageComponent implements OnInit {
                     type: new FormControl({ value: data.type, disabled: !this.editMode }, [Validators.required]),
                     validationDate: new FormControl({ value: data.validationDate !== null ? new Date(data.validationDate) : null, disabled: !this.editMode }),
                     signedResponse: new FormControl({ value: data.signedResponse, disabled: false }),
-                    encodedFile: new FormControl({ value: null, disabled: !this.editMode })
+                    encodedFile: new FormControl({ value: '_CURRENT_FILE', disabled: !this.editMode }, [Validators.required])
                 };
 
                 this.versions = data.versions;
@@ -175,6 +175,9 @@ export class AttachmentPageComponent implements OnInit {
                     attachmentValues[element] = this.attachment[element].value;
                 }
                 if (element === 'encodedFile') {
+                    if (this.attachment[element].value === '_CURRENT_FILE') {
+                        attachmentValues['encodedFile'] = null;
+                    }
                     attachmentValues['format'] = this.appAttachmentViewer.getFile().format;
                 }
             }
@@ -197,10 +200,14 @@ export class AttachmentPageComponent implements OnInit {
                 datas['attachment_' + element] = this.attachment[element].value;
             }
         });
-        datas['resId'] = this.attachment['resIdMaster'].value;
-        this.attachment.encodedFile.setValue(this.appAttachmentViewer.getFile().content);
-        this.appAttachmentViewer.setDatas(datas);
-        if (ev !== 'cleanFile') {
+        if (ev === 'setData') {
+            this.appAttachmentViewer.setDatas(datas);
+        } else if (ev === 'cleanFile') {
+            this.attachment['encodedFile'].setValue(null);
+        } else {
+            datas['resId'] = this.attachment['resIdMaster'].value;
+            this.attachment.encodedFile.setValue(this.appAttachmentViewer.getFile().content);
+            this.appAttachmentViewer.setDatas(datas);
             this.setNewVersion();
         }
     }
diff --git a/src/frontend/app/viewer/document-viewer.component.html b/src/frontend/app/viewer/document-viewer.component.html
index 7dbbf2052f8d70ea0227549a4cb531167257d99a..ceecffcea2c4e39a7904e9bc829a7f970640096d 100644
--- a/src/frontend/app/viewer/document-viewer.component.html
+++ b/src/frontend/app/viewer/document-viewer.component.html
@@ -1,4 +1,4 @@
-<ng-container *ngIf="editInProgress; else elseTemplate">
+<ng-container *ngIf="editInProgress && edition !== 'onlyoffice'; else elseTemplate">
     <div class="editInProgress">
         <i class="fas fa-file-word bounce"></i>
         <div>
@@ -9,7 +9,7 @@
         </div>
     </div>
 </ng-container>
-<ng-template #elseTemplate>
+<ng-container *ngIf="!editInProgress">
     <ng-container *ngIf="noFile; else elseHaveFile">
         <div class="noFile">
             <i class="far fa-times-circle"></i>
@@ -83,4 +83,12 @@
 
         </div>
     </ng-template>
-</ng-template>
\ No newline at end of file
+</ng-container>
+<ng-container *ngIf="editInProgress && edition === 'onlyoffice'">
+    <onlyoffice-viewer #onlyoffice style="height:100%;width:100%;"
+    [onlyofficeKey]="100" 
+    onlyofficeType="docx" 
+    onlyofficeName="Edition"
+    [editMode]="true"
+    [resId]="100"></onlyoffice-viewer>
+</ng-container>
diff --git a/src/frontend/app/viewer/document-viewer.component.ts b/src/frontend/app/viewer/document-viewer.component.ts
index 336b7e23bfe4acdf0ade2f41a356e5c6f0724427..d6d089bbd3dd0b65b8ec2c5eb8280a87a5e75e6b 100644
--- a/src/frontend/app/viewer/document-viewer.component.ts
+++ b/src/frontend/app/viewer/document-viewer.component.ts
@@ -5,7 +5,7 @@ import { NotificationService } from '../notification.service';
 import { HeaderService } from '../../service/header.service';
 import { AppService } from '../../service/app.service';
 import { tap, catchError, finalize, filter, map, exhaustMap } from 'rxjs/operators';
-import { of } from 'rxjs';
+import { of, Subscription } from 'rxjs';
 import { ConfirmComponent } from '../../plugins/modal/confirm.component';
 import { MatDialogRef, MatDialog, MatSidenav } from '@angular/material';
 import { AlertComponent } from '../../plugins/modal/alert.component';
@@ -13,6 +13,7 @@ import { SortPipe } from '../../plugins/sorting.pipe';
 import { templateVisitAll } from '@angular/compiler';
 import { PluginSelectSearchComponent } from '../../plugins/select-search/select-search.component';
 import { FormControl } from '@angular/forms';
+import { EcplOnlyofficeViewerComponent } from '../../plugins/onlyoffice-api-js/onlyoffice-viewer.component';
 
 
 @Component({
@@ -53,6 +54,8 @@ export class DocumentViewerComponent implements OnInit {
 
     intervalLockFile: any;
     editInProgress: boolean = false;
+    edition: string = '';
+
 
     listTemplates: any[] = [];
 
@@ -512,21 +515,26 @@ export class DocumentViewerComponent implements OnInit {
             }),
             filter((data: string) => data === 'ok'),
             tap(() => {
-                this.triggerEvent.emit();
-                const template = this.listTemplates.filter(template => template.id === templateId)[0];
-                this.editInProgress = true;
-                const jnlp: any = {
-                    objectType: 'resourceCreation',
-                    objectId: template.id,
-                    cookie: document.cookie,
-                    data: this.resourceDatas,
-                };
-                this.http.post('../../rest/jnlp', jnlp).pipe(
-                    tap((data: any) => {
-                        window.location.href = '../../rest/jnlp/' + data.generatedJnlp;
-                        this.checkLockFile(data.jnlpUniqueId, template.extension);
-                    })
-                ).subscribe();
+                if (this.edition === 'onlyoffice') {
+                    this.editInProgress = true;                    
+                } else {
+                    this.triggerEvent.emit();
+                    const template = this.listTemplates.filter(template => template.id === templateId)[0];
+                    this.editInProgress = true;
+                    const jnlp: any = {
+                        objectType: 'resourceCreation',
+                        objectId: template.id,
+                        cookie: document.cookie,
+                        data: this.resourceDatas,
+                    };
+                    this.http.post('../../rest/jnlp', jnlp).pipe(
+                        tap((data: any) => {
+                            window.location.href = '../../rest/jnlp/' + data.generatedJnlp;
+                            this.checkLockFile(data.jnlpUniqueId, template.extension);
+                        })
+                    ).subscribe();
+                }
+                
             }),
             catchError((err: any) => {
                 this.notify.handleErrors(err);
@@ -537,6 +545,9 @@ export class DocumentViewerComponent implements OnInit {
 
     editAttachment() {
         this.editInProgress = true;
+
+        this.triggerEvent.emit('setData');
+
         const jnlp: any = {
             objectType: 'attachmentModification',
             objectId: this.resId,
diff --git a/src/frontend/plugins/onlyoffice-api-js/editorConfig.ts b/src/frontend/plugins/onlyoffice-api-js/editorConfig.ts
new file mode 100644
index 0000000000000000000000000000000000000000..88f60c7aa2559b456eda294a6536cc53405660e5
--- /dev/null
+++ b/src/frontend/plugins/onlyoffice-api-js/editorConfig.ts
@@ -0,0 +1,34 @@
+export class EditorConfig {
+  documentType: string;
+  document: {
+    fileType: string;
+    key: string;
+    title: string;
+    url: string;
+    permissions: {
+      comment: boolean;
+      download: boolean;
+      edit: boolean;
+      print: boolean;
+      review: boolean;
+    };
+  };
+  editorConfig: {
+    callbackUrl: string;
+    lang: string;
+    mode: string;
+    customization: {
+      chat: boolean;
+      comments: boolean;
+      compactToolbar: boolean;
+      feedback: boolean;
+      forcesave: boolean;
+      goback: boolean;
+      showReviewChanges: boolean;
+      zoom: number;
+    };
+  };
+  events: {
+    onDocumentStateChange: any;
+  };
+}
diff --git a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-api.js b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-api.js
new file mode 100644
index 0000000000000000000000000000000000000000..5181b6549c4d825b1fa008af89164c2c41617462
--- /dev/null
+++ b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-api.js
@@ -0,0 +1,813 @@
+/**
+ * Copyright (c) Ascensio System SIA 2013. All rights reserved
+ *
+ * http://www.onlyoffice.com
+ */
+var onlyofficetesturl = '';
+
+;(function(DocsAPI, window, document, undefined) {
+
+    /*
+
+        # Full #
+
+        config = {
+            type: 'desktop or mobile',
+            width: '100% by default',
+            height: '100% by default',
+            documentType: 'text' | 'spreadsheet' | 'presentation',
+            document: {
+                title: 'document title',
+                url: 'document url'
+                fileType: 'document file type',
+                options: <advanced options>,
+                key: 'key',
+                vkey: 'vkey',
+                info: {
+                    author: 'author name', // must be deprecated, use owner instead
+                    owner: 'owner name',
+                    folder: 'path to document',
+                    created: '<creation date>', // must be deprecated, use uploaded instead
+                    uploaded: '<uploaded date>',
+                    sharingSettings: [
+                        {
+                            user: 'user name',
+                            permissions: '<permissions>',
+                            isLink: false
+                        },
+                        ...
+                    ]
+                },
+                permissions: {
+                    edit: <can edit>, // default = true
+                    download: <can download>, // default = true
+                    reader: <can view in readable mode>,
+                    review: <can review>, // default = edit
+                    print: <can print>, // default = true
+                    rename: <can rename>, // default = false
+                    changeHistory: <can change history>, // default = false
+                    comment: <can comment in view mode> // default = edit,
+                    modifyFilter: <can add, remove and save filter in the spreadsheet> // default = true
+                    modifyContentControl: <can modify content controls in documenteditor> // default = true
+                   fillForms:  <can edit forms in view mode> // default = edit || review
+                }
+            },
+            editorConfig: {
+                mode: 'view or edit',
+                lang: <language code>,
+                location: <location>,
+                canCoAuthoring: <can coauthoring documents>,
+                canBackToFolder: <can return to folder> - deprecated. use "customization.goback" parameter,
+                createUrl: 'create document url', 
+                sharingSettingsUrl: 'document sharing settings url',
+                fileChoiceUrl: 'source url', // for mail merge or image from storage
+                callbackUrl: <url for connection between sdk and portal>,
+                mergeFolderUrl: 'folder for saving merged file', // must be deprecated, use saveAsUrl instead
+                saveAsUrl: 'folder for saving files'
+                licenseUrl: <url for license>,
+                customerId: <customer id>,
+                region: <regional settings> // can be 'en-us' or lang code
+
+                user: {
+                    id: 'user id',
+                    name: 'user name'
+                },
+                recent: [
+                    {
+                        title: 'document title',
+                        url: 'document url',
+                        folder: 'path to document'
+                    },
+                    ...
+                ],
+                templates: [
+                    {
+                        name: 'template name',
+                        icon: 'template icon url',
+                        url: 'http://...'
+                    },
+                    ...
+                ],
+                customization: {
+                    logo: {
+                        image: url,
+                        imageEmbedded: url,
+                        url: http://...
+                    },
+                    customer: {
+                        name: 'SuperPuper',
+                        address: 'New-York, 125f-25',
+                        mail: 'support@gmail.com',
+                        www: 'www.superpuper.com',
+                        info: 'Some info',
+                        logo: ''
+                    },
+                    about: true,
+                    feedback: {
+                        visible: false,
+                        url: http://...
+                    },
+                    goback: {
+                        url: 'http://...',
+                        text: 'Go to London',
+                        blank: true
+                    },
+                    chat: true,
+                    comments: true,
+                    zoom: 100,
+                    compactToolbar: false,
+                    leftMenu: true,
+                    rightMenu: true,
+                    hideRightMenu: false, // hide or show right panel on first loading
+                    toolbar: true,
+                    statusBar: true,
+                    autosave: true,
+                    forcesave: false,
+                    commentAuthorOnly: false,
+                    showReviewChanges: false,
+                    help: true,
+                    compactHeader: false,
+                    toolbarNoTabs: false,
+                    toolbarHideFileName: false,
+                    reviewDisplay: 'original'
+                },
+                plugins: {
+                    autostart: ['asc.{FFE1F462-1EA2-4391-990D-4CC84940B754}'],
+                    pluginsData: [
+                        "helloworld/config.json",
+                        "chess/config.json",
+                        "speech/config.json",
+                        "clipart/config.json",
+                    ]
+                }
+            },
+            events: {
+                'onAppReady': <application ready callback>,
+                'onBack': <back to folder callback>,
+                'onDocumentStateChange': <document state changed callback>
+                'onDocumentReady': <document ready callback>
+            }
+        }
+
+        # Embedded #
+
+        config = {
+            type: 'embedded',
+            width: '100% by default',
+            height: '100% by default',
+            documentType: 'text' | 'spreadsheet' | 'presentation',
+            document: {
+                title: 'document title',
+                url: 'document url',
+                fileType: 'document file type',
+                key: 'key',
+                vkey: 'vkey'
+            },
+            editorConfig: {
+                licenseUrl: <url for license>,
+                customerId: <customer id>,
+                autostart: 'document',    // action for app's autostart. for presentations default value is 'player'
+                embedded: {
+                     embedUrl: 'url',
+                     fullscreenUrl: 'url',
+                     saveUrl: 'url',
+                     shareUrl: 'url',
+                     toolbarDocked: 'top or bottom'
+                }
+            },
+            events: {
+                'onAppReady': <application ready callback>,
+                'onBack': <back to folder callback>,
+                'onError': <error callback>,
+                'onDocumentReady': <document ready callback>,
+                'onWarning': <warning callback>
+            }
+        }
+    */
+
+    // TODO: allow several instances on one page simultaneously
+
+    DocsAPI.DocEditor = function(placeholderId, config) {
+        var _self = this,
+            _config = config || {};
+
+        extend(_config, DocsAPI.DocEditor.defaultConfig);
+        _config.editorConfig.canUseHistory = _config.events && !!_config.events.onRequestHistory;
+        _config.editorConfig.canHistoryClose = _config.events && !!_config.events.onRequestHistoryClose;
+        _config.editorConfig.canHistoryRestore = _config.events && !!_config.events.onRequestRestore;
+        _config.editorConfig.canSendEmailAddresses = _config.events && !!_config.events.onRequestEmailAddresses;
+        _config.editorConfig.canRequestEditRights = _config.events && !!_config.events.onRequestEditRights;
+        _config.editorConfig.canRequestClose = _config.events && !!_config.events.onRequestClose;
+        _config.editorConfig.canRename = _config.events && !!_config.events.onRequestRename;
+        _config.editorConfig.canMakeActionLink = _config.events && !!_config.events.onMakeActionLink;
+        _config.editorConfig.canRequestUsers = _config.events && !!_config.events.onRequestUsers;
+        _config.editorConfig.canRequestSendNotify = _config.events && !!_config.events.onRequestSendNotify;
+        _config.editorConfig.mergeFolderUrl = _config.editorConfig.mergeFolderUrl || _config.editorConfig.saveAsUrl;
+        _config.editorConfig.canRequestSaveAs = _config.events && !!_config.events.onRequestSaveAs;
+        _config.editorConfig.canRequestInsertImage = _config.events && !!_config.events.onRequestInsertImage;
+        _config.editorConfig.canRequestMailMergeRecipients = _config.events && !!_config.events.onRequestMailMergeRecipients;
+        _config.frameEditorId = placeholderId;
+
+        var onMouseUp = function (evt) {
+            _processMouse(evt);
+        };
+
+        var _attachMouseEvents = function() {
+            if (window.addEventListener) {
+                window.addEventListener("mouseup", onMouseUp, false)
+            } else if (window.attachEvent) {
+                window.attachEvent("onmouseup", onMouseUp);
+            }
+        };
+
+        var _detachMouseEvents = function() {
+            if (window.removeEventListener) {
+                window.removeEventListener("mouseup", onMouseUp, false)
+            } else if (window.detachEvent) {
+                window.detachEvent("onmouseup", onMouseUp);
+            }
+        };
+
+        var _onAppReady = function() {
+            if (_config.type === 'mobile') {
+                document.body.onfocus = function(e) {
+                    setTimeout(function(){
+                        iframe.contentWindow.focus();
+
+                        _sendCommand({
+                            command: 'resetFocus',
+                            data: {}
+                        })
+                    }, 10);
+                };
+            }
+
+            _attachMouseEvents();
+
+            if (_config.editorConfig) {
+                _init(_config.editorConfig);
+            }
+
+            if (_config.document) {
+                _openDocument(_config.document);
+            }
+        };
+
+        var _callLocalStorage = function(data) {
+            if (data.cmd == 'get') {
+                if (data.keys && data.keys.length) {
+                    var af = data.keys.split(','), re = af[0];
+                    for (i = 0; ++i < af.length;)
+                        re += '|' + af[i];
+
+                    re = new RegExp(re); k = {};
+                    for (i in localStorage)
+                        if (re.test(i)) k[i] = localStorage[i];
+                } else {
+                    k = localStorage;
+                }
+
+                _sendCommand({
+                    command: 'internalCommand',
+                    data: {
+                        type: 'localstorage',
+                        keys: k
+                    }
+                });
+            } else
+            if (data.cmd == 'set') {
+                var k = data.keys, i;
+                for (i in k) {
+                    localStorage.setItem(i, k[i]);
+                }
+            }
+        };
+
+        var _onMessage = function(msg) {
+            if ( msg ) {
+                if ( msg.type === "onExternalPluginMessage" ) {
+                    _sendCommand(msg);
+                } else
+                if ( msg.frameEditorId == placeholderId ) {
+                    var events = _config.events || {},
+                        handler = events[msg.event],
+                        res;
+
+                    if (msg.event === 'onRequestEditRights' && !handler) {
+                        _applyEditRights(false, 'handler isn\'t defined');
+                    } else if (msg.event === 'onInternalMessage' && msg.data && msg.data.type == 'localstorage') {
+                        _callLocalStorage(msg.data.data);
+                    } else {
+                        if (msg.event === 'onAppReady') {
+                            _onAppReady();
+                        }
+
+                        if (handler && typeof handler == "function") {
+                            res = handler.call(_self, {target: _self, data: msg.data});
+                        }
+                    }
+                }
+            }
+        };
+
+        var _checkConfigParams = function() {
+            if (_config.document) {
+                if (!_config.document.url || ((typeof _config.document.fileType !== 'string' || _config.document.fileType=='') &&
+                                              (typeof _config.documentType !== 'string' || _config.documentType==''))) {
+                    window.alert("One or more required parameter for the config object is not set");
+                    return false;
+                }
+
+                var appMap = {
+                        'text': 'docx',
+                        'text-pdf': 'pdf',
+                        'spreadsheet': 'xlsx',
+                        'presentation': 'pptx'
+                    }, app;
+
+                if (typeof _config.documentType === 'string' && _config.documentType != '') {
+                    app = appMap[_config.documentType.toLowerCase()];
+                    if (!app) {
+                        window.alert("The \"documentType\" parameter for the config object is invalid. Please correct it.");
+                        return false;
+                    } else if (typeof _config.document.fileType !== 'string' || _config.document.fileType == '') {
+                        _config.document.fileType = app;
+                    }
+                }
+
+                if (typeof _config.document.fileType === 'string' && _config.document.fileType != '') {
+                    var type = /^(?:(xls|xlsx|ods|csv|xlst|xlsy|gsheet|xlsm|xlt|xltm|xltx|fods|ots)|(pps|ppsx|ppt|pptx|odp|pptt|ppty|gslides|pot|potm|potx|ppsm|pptm|fodp|otp)|(doc|docx|doct|odt|gdoc|txt|rtf|pdf|mht|htm|html|epub|djvu|xps|docm|dot|dotm|dotx|fodt|ott))$/
+                                    .exec(_config.document.fileType);
+                    if (!type) {
+                        window.alert("The \"document.fileType\" parameter for the config object is invalid. Please correct it.");
+                        return false;
+                    } else if (typeof _config.documentType !== 'string' || _config.documentType == ''){
+                        if (typeof type[1] === 'string') _config.documentType = 'spreadsheet'; else
+                        if (typeof type[2] === 'string') _config.documentType = 'presentation'; else
+                        if (typeof type[3] === 'string') _config.documentType = 'text';
+                    }
+                }
+
+                var type = /^(?:(pdf|djvu|xps))$/.exec(_config.document.fileType);
+                if (type && typeof type[1] === 'string') {
+                    _config.editorConfig.canUseHistory = false;
+                }
+
+                if (!_config.document.title || _config.document.title=='')
+                    _config.document.title = 'Unnamed.' + _config.document.fileType;
+
+                if (!_config.document.key) {
+                    _config.document.key = 'xxxxxxxxxxxxxxxxxxxx'.replace(/[x]/g, function (c) {var r = Math.random() * 16 | 0; return r.toString(16);});
+                } else if (typeof _config.document.key !== 'string') {
+                    window.alert("The \"document.key\" parameter for the config object must be string. Please correct it.");
+                    return false;
+                }
+
+                _config.document.token = _config.token;
+            }
+            
+            return true;
+        };
+
+        (function() {
+            var result = /[\?\&]placement=(\w+)&?/.exec(window.location.search);
+            if (!!result && result.length) {
+                if (result[1] == 'desktop') {
+                    _config.editorConfig.targetApp = result[1];
+                    // _config.editorConfig.canBackToFolder = false;
+                    if (!_config.editorConfig.customization) _config.editorConfig.customization = {};
+                    _config.editorConfig.customization.about = false;
+                    _config.editorConfig.customization.compactHeader = false;
+
+                    if ( window.AscDesktopEditor ) window.AscDesktopEditor.execCommand('webapps:events', 'loading');
+                }
+            }
+        })();
+
+        var target = document.getElementById(placeholderId),
+            iframe;
+
+        if (target && _checkConfigParams()) {
+            iframe = createIframe(_config);
+            target.parentNode && target.parentNode.replaceChild(iframe, target);
+            var _msgDispatcher = new MessageDispatcher(_onMessage, this);
+        }
+
+        /*
+         cmd = {
+         command: 'commandName',
+         data: <command specific data>
+         }
+         */
+
+        var _destroyEditor = function(cmd) {
+            var target = document.createElement("div");
+            target.setAttribute('id', placeholderId);
+
+            if (iframe) {
+                _msgDispatcher && _msgDispatcher.unbindEvents();
+                _detachMouseEvents();
+                iframe.parentNode && iframe.parentNode.replaceChild(target, iframe);
+            }
+        };
+
+        var _sendCommand = function(cmd) {
+            if (iframe && iframe.contentWindow)
+                postMessage(iframe.contentWindow, cmd);
+        };
+
+        var _init = function(editorConfig) {
+            _sendCommand({
+                command: 'init',
+                data: {
+                    config: editorConfig
+                }
+            });
+        };
+
+        var _openDocument = function(doc) {
+            _sendCommand({
+                command: 'openDocument',
+                data: {
+                    doc: doc
+                }
+            });
+        };
+
+        var _showMessage = function(title, msg) {
+            msg = msg || title;
+            _sendCommand({
+                command: 'showMessage',
+                data: {
+                    msg: msg
+                }
+            });
+        };
+
+        var _applyEditRights = function(allowed, message) {
+            _sendCommand({
+                command: 'applyEditRights',
+                data: {
+                    allowed: allowed,
+                    message: message
+                }
+            });
+        };
+
+        var _processSaveResult = function(result, message) {
+            _sendCommand({
+                command: 'processSaveResult',
+                data: {
+                    result: result,
+                    message: message
+                }
+            });
+        };
+
+        // TODO: remove processRightsChange, use denyEditingRights
+        var _processRightsChange = function(enabled, message) {
+            _sendCommand({
+                command: 'processRightsChange',
+                data: {
+                    enabled: enabled,
+                    message: message
+                }
+            });
+        };
+
+        var _denyEditingRights = function(message) {
+            _sendCommand({
+                command: 'processRightsChange',
+                data: {
+                    enabled: false,
+                    message: message
+                }
+            });
+        };
+
+        var _refreshHistory = function(data, message) {
+            _sendCommand({
+                command: 'refreshHistory',
+                data: {
+                    data: data,
+                    message: message
+                }
+            });
+        };
+
+        var _setHistoryData = function(data, message) {
+            _sendCommand({
+                command: 'setHistoryData',
+                data: {
+                    data: data,
+                    message: message
+                }
+            });
+        };
+
+        var _setEmailAddresses = function(data) {
+            _sendCommand({
+                command: 'setEmailAddresses',
+                data: {
+                    data: data
+                }
+            });
+        };
+
+        var _setActionLink = function (data) {
+            _sendCommand({
+                command: 'setActionLink',
+                data: {
+                    url: data
+                }
+            });
+        };
+
+        var _processMailMerge = function(enabled, message) {
+            _sendCommand({
+                command: 'processMailMerge',
+                data: {
+                    enabled: enabled,
+                    message: message
+                }
+            });
+        };
+
+        var _downloadAs = function (data) {
+            _sendCommand({
+                command: 'downloadAs',
+                data: data
+            });
+        };
+
+        var _setUsers = function(data) {
+            _sendCommand({
+                command: 'setUsers',
+                data: data
+            });
+        };
+
+        var _showSharingSettings = function(data) {
+            _sendCommand({
+                command: 'showSharingSettings',
+                data: data
+            });
+        };
+
+        var _setSharingSettings = function(data) {
+            _sendCommand({
+                command: 'setSharingSettings',
+                data: data
+            });
+        };
+
+        var _insertImage = function(data) {
+            _sendCommand({
+                command: 'insertImage',
+                data: data
+            });
+        };
+
+        var _setMailMergeRecipients = function(data) {
+            _sendCommand({
+                command: 'setMailMergeRecipients',
+                data: data
+            });
+        };
+
+        var _processMouse = function(evt) {
+            var r = iframe.getBoundingClientRect();
+            var data = {
+                type: evt.type,
+                x: evt.x - r.left,
+                y: evt.y - r.top,
+                event: evt
+            };
+
+            _sendCommand({
+                command: 'processMouse',
+                data: data
+            });
+        };
+
+        var _serviceCommand = function(command, data) {
+            _sendCommand({
+                command: 'internalCommand',
+                data: {
+                    command: command,
+                    data: data
+                }
+            });
+        };
+
+        return {
+            showMessage         : _showMessage,
+            processSaveResult   : _processSaveResult,
+            processRightsChange : _processRightsChange,
+            denyEditingRights   : _denyEditingRights,
+            refreshHistory      : _refreshHistory,
+            setHistoryData      : _setHistoryData,
+            setEmailAddresses   : _setEmailAddresses,
+            setActionLink       : _setActionLink,
+            processMailMerge    : _processMailMerge,
+            downloadAs          : _downloadAs,
+            serviceCommand      : _serviceCommand,
+            attachMouseEvents   : _attachMouseEvents,
+            detachMouseEvents   : _detachMouseEvents,
+            destroyEditor       : _destroyEditor,
+            setUsers            : _setUsers,
+            showSharingSettings : _showSharingSettings,
+            setSharingSettings  : _setSharingSettings,
+            insertImage         : _insertImage,
+            setMailMergeRecipients: _setMailMergeRecipients
+        }
+    };
+
+
+    DocsAPI.DocEditor.defaultConfig = {
+        type: 'desktop',
+        width: '100%',
+        height: '100%',
+        editorConfig: {
+            lang: 'en',
+            canCoAuthoring: true,
+            customization: {
+                about: true,
+                feedback: false
+            }
+        }
+    };
+
+    DocsAPI.DocEditor.version = function() {
+        return '5.4.2';
+    };
+
+    MessageDispatcher = function(fn, scope) {
+        var _fn     = fn,
+            _scope  = scope || window,
+            eventFn = function(msg) {
+                _onMessage(msg);
+            };
+
+        var _bindEvents = function() {
+            if (window.addEventListener) {
+                window.addEventListener("message", eventFn, false)
+            }
+            else if (window.attachEvent) {
+                window.attachEvent("onmessage", eventFn);
+            }
+        };
+
+        var _unbindEvents = function() {
+            if (window.removeEventListener) {
+                window.removeEventListener("message", eventFn, false)
+            }
+            else if (window.detachEvent) {
+                window.detachEvent("onmessage", eventFn);
+            }
+        };
+
+        var _onMessage = function(msg) {
+            // TODO: check message origin
+            if (msg && window.JSON) {
+
+                try {
+                    var msg = window.JSON.parse(msg.data);
+                    if (_fn) {
+                        _fn.call(_scope, msg);
+                    }
+                } catch(e) {}
+            }
+        };
+
+        _bindEvents.call(this);
+
+        return {
+            unbindEvents: _unbindEvents
+        }
+    };
+
+    function getBasePath() {
+        return `http://10.2.95.76:8765/web-apps/apps/`;
+        var scripts = document.getElementsByTagName('script'),
+            match;
+
+        for (var i = scripts.length - 1; i >= 0; i--) {
+            match = scripts[i].src.match(/(.*)api\/documents\/api.js/i);
+            if (match) {
+                return match[1];
+            }
+        }
+
+        return "";
+    }
+
+    function getExtensionPath() {
+        if ("undefined" == typeof(extensionParams) || null == extensionParams["url"])
+            return null;
+        return extensionParams["url"] + "apps/";
+    }
+
+    function getAppPath(config) {
+        var extensionPath = getExtensionPath(),
+            path = extensionPath ? extensionPath : getBasePath(),
+            appMap = {
+                'text': 'documenteditor',
+                'text-pdf': 'documenteditor',
+                'spreadsheet': 'spreadsheeteditor',
+                'presentation': 'presentationeditor'
+            },
+            app = appMap['text'];
+
+        if (typeof config.documentType === 'string') {
+            app = appMap[config.documentType.toLowerCase()];
+        } else
+        if (!!config.document && typeof config.document.fileType === 'string') {
+            var type = /^(?:(xls|xlsx|ods|csv|xlst|xlsy|gsheet|xlsm|xlt|xltm|xltx|fods|ots)|(pps|ppsx|ppt|pptx|odp|pptt|ppty|gslides|pot|potm|potx|ppsm|pptm|fodp|otp))$/
+                            .exec(config.document.fileType);
+            if (type) {
+                if (typeof type[1] === 'string') app = appMap['spreadsheet']; else
+                if (typeof type[2] === 'string') app = appMap['presentation'];
+            }
+        }
+
+        path += app + "/";
+        path += config.type === "mobile"
+            ? "mobile"
+            : config.type === "embedded"
+                ? "embed"
+                : "main";
+        path += "/index.html";
+
+        return path;
+    }
+
+    function getAppParameters(config) {
+        var params = "?_dc=5.4.2-46";
+
+        if (config.editorConfig && config.editorConfig.lang)
+            params += "&lang=" + config.editorConfig.lang;
+
+        if (config.editorConfig && config.editorConfig.targetApp!=='desktop') {
+            if ( (typeof(config.editorConfig.customization) == 'object') && config.editorConfig.customization.loaderName) {
+                if (config.editorConfig.customization.loaderName !== 'none') params += "&customer=" + config.editorConfig.customization.loaderName;
+            } else
+                params += "&customer=ONLYOFFICE";
+            if ( (typeof(config.editorConfig.customization) == 'object') && config.editorConfig.customization.loaderLogo) {
+                if (config.editorConfig.customization.loaderLogo !== '') params += "&logo=" + config.editorConfig.customization.loaderLogo;
+            }
+        }
+
+        if (config.frameEditorId)
+            params += "&frameEditorId=" + config.frameEditorId;
+        
+        return params;
+    }
+
+    function createIframe(config) {
+        var iframe = document.createElement("iframe");
+
+        iframe.src = getAppPath(config) + getAppParameters(config);
+        iframe.width = config.width;
+        iframe.height = config.height;
+        iframe.align = "top";
+        iframe.frameBorder = 0;
+        iframe.name = "frameEditor";
+        iframe.allowFullscreen = true;
+        iframe.setAttribute("allowfullscreen",""); // for IE11
+        iframe.setAttribute("onmousewheel",""); // for Safari on Mac
+		
+		if (config.type == "mobile")
+		{
+			iframe.style.position = "fixed";
+            iframe.style.overflow = "hidden";
+            document.body.style.overscrollBehaviorY = "contain";
+		}
+        return iframe;
+    }
+
+    function postMessage(wnd, msg) {
+        if (wnd && wnd.postMessage && window.JSON) {
+            // TODO: specify explicit origin
+            wnd.postMessage(window.JSON.stringify(msg), "*");
+        }
+
+    }
+
+    function extend(dest, src) {
+        for (var prop in src) {
+            if (src.hasOwnProperty(prop)) {
+                if (typeof dest[prop] === 'undefined') {
+                    dest[prop] = src[prop];
+                } else
+                if (typeof dest[prop] === 'object' &&
+                        typeof src[prop] === 'object') {
+                    extend(dest[prop], src[prop])
+                }
+            }
+        }
+        return dest;
+    }
+
+})(window.DocsAPI = window.DocsAPI || {}, window, document);
+
diff --git a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.css b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..ab1fc9910a0894f57cbc50ee127d22f0ce88fdf7
--- /dev/null
+++ b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.css
@@ -0,0 +1,69 @@
+.onlyoffice-modal {
+    width: 100%;
+    height: 100%;
+    position: fixed;
+    left: 0;
+    right: 0;
+    top: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, .5);
+    z-index: 10001;
+    padding: 15px;
+}
+
+.modal-dialog {
+    background-color: #fff;
+    border: 1px solid #f2f2f2;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    width: 100%;
+    height: 100%;
+    display: table;
+}
+
+.modal-header {
+    height: 6%;
+    padding: 5px;
+    display: table-row
+}
+
+h3 {
+    margin-top: 0;
+    margin-bottom: 0;
+    font-size: 16px;
+    padding: 5px;
+}
+
+button.pull-right {
+    padding: 0 12px;
+    background: none;
+    outline: none;
+    border: none;
+    font-size: 25px;
+    position: absolute;
+    top: 0;
+    right: 0;
+    border-left: 1px solid #dedede;
+    color: #dedede;
+}
+
+.modal-body {
+    width: 100%;
+    max-height: 94%;
+    overflow: auto;
+    padding: 0px;
+    background: #dedede;
+    display: table-cell;
+    text-align: center;
+    vertical-align: middle;
+}
+
+.modal-body .scroller {
+    max-height: 94%;
+    overflow: auto;
+}
+
+.onlyoffice-icon-header {
+    width: 20px;
+    height: auto;
+}
\ No newline at end of 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
new file mode 100644
index 0000000000000000000000000000000000000000..652cdc932dd7bbff703957d512ec2c2a95840265
--- /dev/null
+++ b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.html
@@ -0,0 +1,19 @@
+<a href="javascript:void(0)" (click)="showModal()" id="onlyoffice-file-{{id}}">
+    <img src="/src/images/{{onlyofficeType}}.png" alt="Office File">
+</a>
+
+<div class="onlyoffice-modal" [hidden]="!showModalWindow" id="onlyoffice-pop-{{id}}">
+    <div class="modal-dialog">
+        <div class="modal-header">
+            <div style="padding: 5px;">
+                <img src="/src/images/{{onlyofficeType}}.png" alt="Office File" class="onlyoffice-icon-header pull-left">
+                <h3 class="pull-left">{{onlyofficeName}}</h3>
+            </div>
+            <button (click)="hideModal()" class="pull-right">x</button>
+        </div>
+        <div class="modal-body">
+            <div id="placeholder"></div>
+        </div>
+    </div>
+
+</div>
\ No newline at end of file
diff --git a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..27b0b12ce7be08d09c236d2646fbaf39b49167d5
--- /dev/null
+++ b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts
@@ -0,0 +1,120 @@
+import {
+    Component,
+    OnInit,
+    AfterViewInit,
+    Input,
+    NgZone,
+    EventEmitter,
+    Output,
+    HostListener
+} from '@angular/core';
+import './onlyoffice-api.js';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { Subject, Observable, of } from 'rxjs';
+import { catchError, tap } from 'rxjs/operators';
+
+declare var DocsAPI: any;
+
+@Component({
+    selector: 'onlyoffice-viewer',
+    template: `<button (click)="quit()">close</button><div id="placeholder"></div>`,
+})
+export class EcplOnlyofficeViewerComponent implements OnInit, AfterViewInit {
+    @Input() id: string;
+    @Input() onlyofficeName: string;
+    @Input() onlyofficeType: string;
+    @Input() onlyofficeKey: string;
+    @Input() resId: number;
+    @Input() editMode: boolean = false;
+
+    @Output() triggerEvent = new EventEmitter<string>();
+
+    editorConfig: any;
+    docEditor: any;
+    showModalWindow: boolean = false;
+
+    @HostListener('window:message',['$event'])
+    onMessage(e: any) {
+        console.log(e);
+        const response = JSON.parse(e.data);
+        
+        if (response.event === 'onDownloadAs') {
+            this.onDownloadAs(response.data);
+        }
+    }
+    constructor(private zone: NgZone, public http: HttpClient) { }    
+
+    quit() {
+        this.docEditor.downloadAs();
+        //this.docEditor.destroyEditor();
+    }
+
+    onDocumentStateChange(event: any) {
+        if (event.data) {
+            console.log('The document changed');
+            console.log(event);
+        } else {
+            console.log('Changes are collected on document editing service');
+        }
+    }
+
+    onDownloadAs(url: any) {
+        const optionRequete = {
+            headers: new HttpHeaders({ 
+              'Access-Control-Allow-Origin':'*',
+            })
+          };
+        this.http.get(url, optionRequete).pipe(
+            tap((data: any) => {
+                console.log(data);
+            }),
+            catchError((err: any) => {
+                console.log(err)
+                return of(false);
+            })
+        ).subscribe();
+    }
+    
+
+    ngOnInit() { }
+
+    ngAfterViewInit() {
+        this.editorConfig = {
+            documentType: 'text',
+            document: {
+                fileType: 'odt',
+                key: 'toto',
+                title: this.onlyofficeName,
+                url: `http://10.2.95.76/rep_standard.odt`,
+                permissions: {
+                    comment: false,
+                    download: true,
+                    edit: this.editMode,
+                    print: true,
+                    review: false
+                }
+            },
+            editorConfig: {
+                callbackUrl: 'http://10.2.95.76/maarch_courrier_develop/rest/test',
+                lang: 'fr-FR',
+                mode: 'edit',
+                customization: {
+                    chat: false,
+                    comments: false,
+                    compactToolbar: false,
+                    feedback: false,
+                    forcesave: false,
+                    goback: false,
+                    hideRightMenu: true,
+                    showReviewChanges: false,
+                    zoom: 100
+                },
+                user: {
+                    id: "1",
+                    name: "Bernard BLIER"
+                },
+            },
+        };
+        this.docEditor = new DocsAPI.DocEditor('placeholder', this.editorConfig);
+    }
+}