diff --git a/rest/index.php b/rest/index.php
index 484081120f3e588c76114b361c20455ba2a058ec..6bd5d7cb8ba7d9b5a5f45e0eedafcfefc29ad6a3 100755
--- a/rest/index.php
+++ b/rest/index.php
@@ -603,6 +603,7 @@ $app->post('/wopi/files/{id}/contents', \ContentManagement\controllers\Collabora
 $app->post('/collaboraOnline/configuration', \ContentManagement\controllers\CollaboraOnlineController::class . ':getConfiguration');
 $app->get('/collaboraOnline/available', \ContentManagement\controllers\CollaboraOnlineController::class . ':isAvailable');
 $app->post('/collaboraOnline/file', \ContentManagement\controllers\CollaboraOnlineController::class . ':getTmpFile');
+$app->delete('/collaboraOnline/file', \ContentManagement\controllers\CollaboraOnlineController::class . ':deleteTmpFile');
 $app->post('/collaboraOnline/encodedFile', \ContentManagement\controllers\CollaboraOnlineController::class . ':saveTmpEncodedDocument');
 
 $app->run();
diff --git a/src/app/contentManagement/controllers/CollaboraOnlineController.php b/src/app/contentManagement/controllers/CollaboraOnlineController.php
index d1ed6f54014bd7987a498ba5fbae32d340f1a3b2..b00dce26a8dc7e9336ade5c9cdebce4be86f9269 100644
--- a/src/app/contentManagement/controllers/CollaboraOnlineController.php
+++ b/src/app/contentManagement/controllers/CollaboraOnlineController.php
@@ -232,6 +232,10 @@ class CollaboraOnlineController
         $tmpPath = CoreConfigModel::getTmpPath();
         $pathToDocument = $tmpPath . $filename;
 
+        if (!file_exists($pathToDocument)) {
+            return $response->withStatus(404)->withJson(['errors' => 'Document not found']);
+        }
+
         if ($tokenCheckResult['mode'] == 'creation' && ($tokenCheckResult['type'] == 'resource' || $tokenCheckResult['type'] == 'attachment')) {
             $dataToMerge = ['userId' => $GLOBALS['id']];
             if (!empty($body['data']) && is_array($body['data'])) {
@@ -252,11 +256,44 @@ class CollaboraOnlineController
             $content = base64_encode($fileContent);
         }
 
-        unlink($pathToDocument);
-
         return $response->withJson(['content' => $content, 'format' => $extension]);
     }
 
+    public function deleteTmpFile(Request $request, Response $response)
+    {
+        $queryParams = $request->getQueryParams();
+
+        if (!Validator::stringType()->notEmpty()->validate($queryParams['token'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Query token is empty or not a string']);
+        }
+
+        $tokenCheckResult = CollaboraOnlineController::checkToken(['token' => $queryParams['token']]);
+        if (!empty($tokenCheckResult['errors'])) {
+            return $response->withStatus($tokenCheckResult['code'])->withJson(['errors' => $tokenCheckResult['errors']]);
+        }
+
+        $document = CollaboraOnlineController::getDocument([
+            'id'     => $tokenCheckResult['resId'],
+            'type'   => $tokenCheckResult['type'],
+            'mode'   => $tokenCheckResult['mode'],
+            'format' => $tokenCheckResult['format']
+        ]);
+        if (!empty($document['errors'])) {
+            return $response->withStatus($document['code'])->withJson(['errors' => $document['errors']]);
+        }
+
+        $extension = pathinfo($document['filename'], PATHINFO_EXTENSION);
+        $filename = "collabora_{$GLOBALS['id']}_{$tokenCheckResult['type']}_{$tokenCheckResult['mode']}_{$tokenCheckResult['resId']}.{$extension}";
+        $tmpPath = CoreConfigModel::getTmpPath();
+        $pathToDocument = $tmpPath . $filename;
+
+        if (file_exists($pathToDocument)) {
+            unlink($pathToDocument);
+        }
+
+        return $response->withStatus(204);
+    }
+
     public static function isAvailable(Request $request, Response $response)
     {
         $loadedXml = CoreConfigModel::getXmlLoaded(['path' => 'apps/maarch_entreprise/xml/documentEditorsConfig.xml']);
@@ -301,12 +338,16 @@ class CollaboraOnlineController
         if (!empty($body['format']) && !Validator::stringType()->validate($body['format'])) {
             return $response->withStatus(400)->withJson(['errors' => 'Body format is not a string']);
         }
+        if (!empty($body['path']) && !Validator::stringType()->validate($body['path'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Body path is not a string']);
+        }
 
         $document = CollaboraOnlineController::getDocument([
             'id'     => $body['resId'],
             'type'   => $body['type'],
             'mode'   => $body['mode'],
-            'format' => $body['format']
+            'format' => $body['format'],
+            'path'   => $body['path']
         ]);
 
         if (!empty($document['errors'])) {
@@ -444,7 +485,7 @@ class CollaboraOnlineController
     private static function getDocument(array $args)
     {
         ValidatorModel::notEmpty($args, ['id', 'type', 'mode']);
-        ValidatorModel::stringType($args, ['type', 'mode', 'format']);
+        ValidatorModel::stringType($args, ['type', 'mode', 'format', 'path']);
         ValidatorModel::intVal($args, ['id']);
 
         if ($args['mode'] == 'creation' && ($args['type'] == 'resource' || $args['type'] == 'attachment')) {
@@ -547,6 +588,47 @@ class CollaboraOnlineController
             $document['docserver_id'] = '';
             $document['path'] = CoreConfigModel::getTmpPath();
 
+            $document['modification_date'] = new \DateTime('now');
+            $document['modification_date'] = $document['modification_date']->format(\DateTime::ISO8601);
+        } else if ($args['type'] == 'template' && $args['mode'] == 'creation') {
+            if (!PrivilegeController::hasPrivilege(['privilegeId' => 'admin_templates', 'userId' => $GLOBALS['id']])) {
+                return ['code' => 403, 'errors' => 'Service forbidden'];
+            }
+
+            $document['filename'] = "collabora_template_{$GLOBALS['id']}_{$args['id']}.{$args['format']}";
+            $document['docserver_id'] = '';
+            $document['path'] = CoreConfigModel::getTmpPath();
+
+            if (!file_exists($document['path'] . $document['filename'])) {
+                if (empty($args['path'])) {
+                    return ['code' => 400, 'errors' => 'Argument path is missing'];
+                }
+
+                $customId = CoreConfigModel::getCustomId();
+                if (!empty($customId) && is_dir("custom/{$customId}/modules/templates/templates/styles/")) {
+                    $stylesPath = "custom/{$customId}/modules/templates/templates/styles/";
+                } else {
+                    $stylesPath = 'modules/templates/templates/styles/';
+                }
+                if (strpos($args['path'], $stylesPath) !== 0 || substr_count($args['path'], '.') != 1) {
+                    return ['code' => 400, 'errors' => 'Template path is not valid'];
+                }
+
+                if (!file_exists($args['path'])) {
+                    return ['code' => 400, 'errors' => 'Document does not exists'];
+                }
+
+                $fileContent = file_get_contents($args['path']);
+                if ($fileContent === false) {
+                    return ['code' => 400, 'errors' => 'Document does not exists'];
+                }
+
+                $result = file_put_contents($document['path'] . $document['filename'], $fileContent);
+                if ($result === false) {
+                    return ['code' => 400, 'errors' => 'Document does not exists'];
+                }
+            }
+
             $document['modification_date'] = new \DateTime('now');
             $document['modification_date'] = $document['modification_date']->format(\DateTime::ISO8601);
         } else {
diff --git a/src/app/template/controllers/TemplateController.php b/src/app/template/controllers/TemplateController.php
index 76a892761a0d6be0545c687eb21e486245084d02..e20e10d692d9a5d91f7b4f8f2557a04da79041fc 100755
--- a/src/app/template/controllers/TemplateController.php
+++ b/src/app/template/controllers/TemplateController.php
@@ -28,7 +28,6 @@ use Resource\models\ResModel;
 use Respect\Validation\Validator;
 use Slim\Http\Request;
 use Slim\Http\Response;
-use SrcCore\models\CoreConfigModel;
 use SrcCore\models\ValidatorModel;
 use Template\models\TemplateAssociationModel;
 use Template\models\TemplateModel;
@@ -46,7 +45,8 @@ class TemplateController
         'application/vnd.openxmlformats-officedocument.presentationml‌.slideshow',
         'application/vnd.oasis.opendocument.text',
         'application/vnd.oasis.opendocument.presentation',
-        'application/vnd.oasis.opendocument.spreadsheet'
+        'application/vnd.oasis.opendocument.spreadsheet',
+        'application/octet-stream'
     ];
 
     public function get(Request $request, Response $response)
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
index dda9091a33128a2785c06cb3c7a75ac17b85836f..c7adb7898d1d22e18f0d5a2357f9fbade89f9a85 100644
--- 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
@@ -2,15 +2,15 @@
     <mat-dialog-content style="padding: 0px;">
         <onlyoffice-viewer *ngIf="editorType === 'onlyoffice'" #onlyofficeViewer style="height:100%;width:100%;" [hideCloseEditor]="true"
             [params]="editorOptions" [file]="file" [editMode]="true" (triggerAfterUpdatedDoc)="close()"
-            (triggerCloseEditor)="dialogRef.close('');"></onlyoffice-viewer>
+            (triggerCloseEditor)="dialogRef.close('');" (triggerModifiedDocument)="documentIsModified = true"></onlyoffice-viewer>
         <app-collabora-online-viewer *ngIf="editorType === 'collaboraonline'" #collaboraOnlineViewer style="height:100%;width:100%;" [params]="editorOptions" [file]="file"
                                      [editMode]="true" (triggerAfterUpdatedDoc)="close()"
-                                         (triggerCloseEditor)="dialogRef.close('');"></app-collabora-online-viewer>
+                                         (triggerCloseEditor)="dialogRef.close('');" (triggerModifiedDocument)="documentIsModified = true"></app-collabora-online-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>
+            (click)="close()" [disabled]="!documentIsModified">{{lang.validate}}</button>
         <button mat-raised-button mat-button [disabled]="loading" [mat-dialog-close]="">{{lang.cancel}}</button>
     </div>
 </div>
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
index 6302aca25b0b3a7be0718c5fab5a968983e1d519..59fb909d0e6c1b8193f4fd768386fc7cf862ae3f 100644
--- 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
@@ -17,6 +17,7 @@ export class TemplateFileEditorModalComponent implements OnInit {
     editorOptions: any = null;
     file: any = null;
     editorType: any = null;
+    documentIsModified: boolean = false;
 
     @ViewChild('onlyofficeViewer', { static: false }) onlyofficeViewer: EcplOnlyofficeViewerComponent;
     @ViewChild('collaboraOnlineViewer', { static: false }) collaboraOnlineViewer: CollaboraOnlineViewerComponent;
diff --git a/src/frontend/app/viewer/document-viewer.component.ts b/src/frontend/app/viewer/document-viewer.component.ts
index 9634b14a422691e3f736bb3b3278c36022c9fcae..b4f9214933015e76844845a67579e7d80545f5c9 100755
--- a/src/frontend/app/viewer/document-viewer.component.ts
+++ b/src/frontend/app/viewer/document-viewer.component.ts
@@ -4,7 +4,7 @@ import { LANG } from '../translate.component';
 import { NotificationService } from '../../service/notification/notification.service';
 import { HeaderService } from '../../service/header.service';
 import { AppService } from '../../service/app.service';
-import { tap, catchError, filter, map, exhaustMap } from 'rxjs/operators';
+import {tap, catchError, filter, map, exhaustMap, take} from 'rxjs/operators';
 import { ConfirmComponent } from '../../plugins/modal/confirm.component';
 import { MatDialogRef, MatDialog } from '@angular/material/dialog';
 import { AlertComponent } from '../../plugins/modal/alert.component';
@@ -493,6 +493,13 @@ export class DocumentViewerComponent implements OnInit {
                 resolve(this.getBase64Document(this.file.src));
             } else {
                 this.getFile().pipe(
+                    take(1),
+                    tap((data: any) => {
+                        if (this.editor.mode === 'collaboraOnline' && this.collaboraOnlineViewer !== undefined) {
+                            this.collaboraOnlineViewer.isSaving = false;
+                        }
+                        return data;
+                    }),
                     exhaustMap((data: any) => this.http.post(`../rest/convertedFile`, { name: `${data.name}.${data.format}`, base64: `${data.content}` })),
                     tap((data: any) => {
                         resolve(data.encodedResource);
diff --git a/src/frontend/plugins/collabora-online/collabora-online-viewer.component.ts b/src/frontend/plugins/collabora-online/collabora-online-viewer.component.ts
index 705175db3ddcdb57b9254b70a98bcdc8955a8166..9617323edb178551022c424805b8c0c8d0c40ce6 100644
--- a/src/frontend/plugins/collabora-online/collabora-online-viewer.component.ts
+++ b/src/frontend/plugins/collabora-online/collabora-online-viewer.component.ts
@@ -35,6 +35,7 @@ export class CollaboraOnlineViewerComponent implements OnInit, AfterViewInit, On
     editorConfig: any;
     key: number = 0;
     isSaving: boolean = false;
+    isModified: boolean = false;
     fullscreenMode: boolean = false;
 
     allowedExtension: string[] = [
@@ -67,11 +68,18 @@ export class CollaboraOnlineViewerComponent implements OnInit, AfterViewInit, On
         // console.log(e);
         const response = JSON.parse(e.data);
         // EVENT TO CONSTANTLY UPDATE CURRENT DOCUMENT
-        if (response.MessageId === 'Doc_ModifiedStatus' && response.Values.Modified === false && this.isSaving) {
+        if (response.MessageId === 'Doc_ModifiedStatus' && response.Values.Modified === false) {
+            this.isModified = false;
+        }
+        if (response.MessageId === 'Action_Save_Resp' && response.Values.success === true && !this.isModified) {
+            this.triggerAfterUpdatedDoc.emit();
+            this.getTmpFile();
+        } else if (response.MessageId === 'Doc_ModifiedStatus' && response.Values.Modified === false && this.isSaving) {
             // Collabora sends 'Action_Save_Resp' when it starts saving the document, then sends Doc_ModifiedStatus with Modified = false when it is done saving
             this.triggerAfterUpdatedDoc.emit();
             this.getTmpFile();
         } else if (response.MessageId === 'Doc_ModifiedStatus' && response.Values.Modified === true) {
+            this.isModified = true;
             this.triggerModifiedDocument.emit();
         } else if (response.MessageId === 'App_LoadingStatus' && response.Values.Status === 'Document_Loaded') {
             const message = {'MessageId': 'Host_PostmessageReady'};
@@ -110,6 +118,8 @@ export class CollaboraOnlineViewerComponent implements OnInit, AfterViewInit, On
         };
         this.collaboraFrame.nativeElement.contentWindow.postMessage(JSON.stringify(message), '*');
 
+        this.deleteTmpFile();
+
         this.triggerAfterUpdatedDoc.emit();
         this.triggerCloseEditor.emit();
     }
@@ -123,7 +133,7 @@ export class CollaboraOnlineViewerComponent implements OnInit, AfterViewInit, On
                 'Notify': true,
                 'ExtendedData': 'FinalSave=True',
                 'DontTerminateEdit': true,
-                'DontSaveIfUnmodified': true
+                'DontSaveIfUnmodified': false
             }
         };
         this.collaboraFrame.nativeElement.contentWindow.postMessage(JSON.stringify(message), '*');
@@ -140,7 +150,11 @@ export class CollaboraOnlineViewerComponent implements OnInit, AfterViewInit, On
                 this.params.objectType = 'template';
             }
 
-            if (typeof this.params.objectId === 'string' && this.params.objectType === 'encodedResource') {
+            this.params.objectPath = undefined;
+            if (typeof this.params.objectId === 'string' && this.params.objectType === 'template') {
+                this.params.objectPath = this.params.objectId;
+                this.params.objectId = this.key;
+            } else if (typeof this.params.objectId === 'string' && this.params.objectType === 'encodedResource') {
                 this.params.content = this.params.objectId;
                 this.params.objectId = this.key;
                 this.params.objectMode = 'encoded';
@@ -214,6 +228,21 @@ export class CollaboraOnlineViewerComponent implements OnInit, AfterViewInit, On
         });
     }
 
+    deleteTmpFile() {
+        return new Promise((resolve) => {
+            this.http.delete('../rest/collaboraOnline/file?token=' + this.token).pipe(
+                tap(() => {
+                    resolve(true);
+                }),
+                catchError((err) => {
+                    this.notify.handleErrors(err);
+                    this.triggerCloseEditor.emit();
+                    return of(false);
+                }),
+            ).subscribe();
+        });
+    }
+
     saveEncodedFile() {
         return new Promise((resolve) => {
             this.http.post('../rest/collaboraOnline/encodedFile', {content: this.params.content, format: this.file.format, key: this.key}).pipe(
@@ -249,7 +278,8 @@ export class CollaboraOnlineViewerComponent implements OnInit, AfterViewInit, On
                 resId: this.params.objectId,
                 type: this.params.objectType,
                 mode: this.params.objectMode,
-                format: this.file.format
+                format: this.file.format,
+                path: this.params.objectPath
             }).pipe(
                 tap((data: any) => {
                     this.editorUrl = data.url;