diff --git a/services/web/app/views/project/editor.pug b/services/web/app/views/project/editor.pug
index 6f10ac05de..5177c0afe2 100644
--- a/services/web/app/views/project/editor.pug
+++ b/services/web/app/views/project/editor.pug
@@ -120,6 +120,31 @@ block content
.modal-footer
button.btn.btn-info(ng-click="done()") #{translate("ok")}
+ script(type="text/ng-template", id="outOfSyncModalTemplate")
+ .modal-header
+ button.close(
+ type="button"
+ data-dismiss="modal"
+ ng-click="done()"
+ aria-label="Close"
+ )
+ span(aria-hidden="true") ×
+ h3 {{ title }}
+ .modal-body(ng-bind-html="message")
+
+ .modal-body
+ button.btn.btn-info(
+ ng-init="showFileContents = false"
+ ng-click="showFileContents = !showFileContents"
+ )
+ | {{showFileContents ? "Hide" : "Show"}} Local File Contents
+ .text-preview(ng-show="showFileContents")
+ .scroll-container
+ | {{editorContent}}
+
+ .modal-footer
+ button.btn.btn-info(ng-click="done()") #{translate("ok")}
+
script(type="text/ng-template", id="lockEditorModalTemplate")
.modal-header
h3 {{ title }}
diff --git a/services/web/frontend/js/ide/editor/EditorManager.js b/services/web/frontend/js/ide/editor/EditorManager.js
index eccc19b957..ab8eb8913c 100644
--- a/services/web/frontend/js/ide/editor/EditorManager.js
+++ b/services/web/frontend/js/ide/editor/EditorManager.js
@@ -237,9 +237,10 @@ define([
} else {
this.ide.socket.disconnect()
this.ide.reportError(error, meta)
- this.ide.showGenericMessageModal(
+ this.ide.showOutOfSyncModal(
'Out of sync',
- "Sorry, this file has gone out of sync and we need to do a full refresh.
Please see this help guide for more information"
+ "Sorry, this file has gone out of sync and we need to do a full refresh.
Please see this help guide for more information",
+ sharejs_doc.doc._doc.snapshot
)
}
const removeHandler = this.$scope.$on('project:joined', () => {
diff --git a/services/web/frontend/js/ide/editor/controllers/SavingNotificationController.js b/services/web/frontend/js/ide/editor/controllers/SavingNotificationController.js
index fcb0d339dd..b08a67c33f 100644
--- a/services/web/frontend/js/ide/editor/controllers/SavingNotificationController.js
+++ b/services/web/frontend/js/ide/editor/controllers/SavingNotificationController.js
@@ -26,6 +26,7 @@ define(['../../../base', '../Document'], (App, Document) =>
})
let lockEditorModal = null // modal showing "connection lost"
+ let originalPermissionsLevel
const MAX_UNSAVED_SECONDS = 15 // lock the editor after this time if unsaved
$scope.docSavingStatus = {}
@@ -62,11 +63,24 @@ define(['../../../base', '../Document'], (App, Document) =>
'Connection lost',
'Sorry, the connection to the server is down.'
)
- lockEditorModal.result.finally(() => (lockEditorModal = null)) // unset the modal if connection comes back
+
+ // put editor in readOnly mode
+ originalPermissionsLevel = ide.$scope.permissionsLevel
+ ide.$scope.permissionsLevel = 'readOnly'
+
+ lockEditorModal.result.finally(() => {
+ lockEditorModal = null // unset the modal if connection comes back
+ // restore original permissions
+ ide.$scope.permissionsLevel = originalPermissionsLevel
+ })
}
if (lockEditorModal && newUnsavedCount === 0) {
lockEditorModal.dismiss('connection back up')
+ // restore original permissions if they were changed
+ if (originalPermissionsLevel) {
+ ide.$scope.permissionsLevel = originalPermissionsLevel
+ }
}
// for performance, only update the display if the old or new
diff --git a/services/web/frontend/js/ide/permissions/PermissionsManager.js b/services/web/frontend/js/ide/permissions/PermissionsManager.js
index 9d0e9c97cd..4853c7003d 100644
--- a/services/web/frontend/js/ide/permissions/PermissionsManager.js
+++ b/services/web/frontend/js/ide/permissions/PermissionsManager.js
@@ -27,6 +27,8 @@ define([], function() {
if (permissionsLevel != null) {
if (permissionsLevel === 'readOnly') {
this.$scope.permissions.read = true
+ this.$scope.permissions.write = false
+ this.$scope.permissions.admin = false
this.$scope.permissions.comment = true
} else if (permissionsLevel === 'readAndWrite') {
this.$scope.permissions.read = true
diff --git a/services/web/frontend/js/ide/services/ide.js b/services/web/frontend/js/ide/services/ide.js
index d2da385a74..c7964975e4 100644
--- a/services/web/frontend/js/ide/services/ide.js
+++ b/services/web/frontend/js/ide/services/ide.js
@@ -91,12 +91,30 @@ define(['../../base'], function(App) {
}
})
+ ide.showOutOfSyncModal = (title, message, editorContent) =>
+ $modal.open({
+ templateUrl: 'outOfSyncModalTemplate',
+ controller: 'OutOfSyncModalController',
+ resolve: {
+ title() {
+ return title
+ },
+ message() {
+ return message
+ },
+ editorContent() {
+ return editorContent
+ }
+ },
+ windowClass: 'out-of-sync-modal'
+ })
+
ide.showLockEditorMessageModal = (title, message) =>
// modal to block the editor when connection is down
$modal.open({
templateUrl: 'lockEditorModalTemplate',
controller: 'GenericMessageModalController',
- backdrop: 'static', // prevent dismiss by click on background
+ backdrop: false, // not dismissable by clicking background
keyboard: false, // prevent dismiss via keyboard
resolve: {
title() {
@@ -112,7 +130,7 @@ define(['../../base'], function(App) {
return ide
})
- return App.controller('GenericMessageModalController', function(
+ App.controller('GenericMessageModalController', function(
$scope,
$modalInstance,
title,
@@ -123,6 +141,20 @@ define(['../../base'], function(App) {
return ($scope.done = () => $modalInstance.close())
})
+
+ App.controller('OutOfSyncModalController', function(
+ $scope,
+ $modalInstance,
+ title,
+ message,
+ editorContent
+ ) {
+ $scope.title = title
+ $scope.message = message
+ $scope.editorContent = editorContent
+
+ return ($scope.done = () => $modalInstance.close())
+ })
})
function __guard__(value, transform) {
diff --git a/services/web/frontend/stylesheets/app/editor.less b/services/web/frontend/stylesheets/app/editor.less
index cf0320f4c6..ee0a93cf1c 100644
--- a/services/web/frontend/stylesheets/app/editor.less
+++ b/services/web/frontend/stylesheets/app/editor.less
@@ -518,8 +518,32 @@ CodeMirror
.modal.lock-editor-modal {
display: flex !important;
+ background-color: rgba(0, 0, 0, 0.3);
+ overflow-y: hidden;
+ pointer-events: none;
.modal-dialog {
- margin: auto;
+ top: @line-height-computed;
+ }
+}
+
+.out-of-sync-modal {
+ .text-preview {
+ margin-top: @line-height-computed / 2;
+ .scroll-container {
+ max-height: 360px;
+ background-color: white;
+ font-size: 0.8em;
+ line-height: 1.1em;
+ overflow: auto;
+ border: 1px solid @gray-lighter;
+ padding-left: 12px;
+ padding-right: 12px;
+ padding-top: 8px;
+ padding-bottom: 8px;
+ text-align: left;
+ white-space: pre;
+ font-family: monospace;
+ }
}
}