Fix error handling for save / manual save (#137)

This commit is contained in:
korelstar 2017-11-13 13:12:45 +01:00 committed by Hendrik Leppelsack
parent 7182d31907
commit 2eea48b05d
10 changed files with 88 additions and 42 deletions

View File

@ -136,22 +136,35 @@
position: relative;
padding: 0 45px 30px 45px;
margin: -10px 0 0;
opacity: .4;
-ms-user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
z-index: 5;
}
#app-content .note-meta > * {
opacity: .4;
}
#app-content .note-meta > .note-error {
opacity: 1;
background-color: #e00;
color: #fff;
border-radius: 0.5ex;
padding: 0.5ex 1ex;
}
#app-content .note-meta-right {
float: right;
}
#app-content .saving {
background: url('../img/loading.gif') no-repeat right 15px top 15px / 24px !important;
/* Overrides the snap.js animation making the loading icon to fly in app-content. */
transition: none !important;
-webkit-transition: none !important;
#app-content .note-meta > .saving {
display: inline-block;
vertical-align: middle;
width: 2.5ex;
height: 2.5ex;
background: url('../img/loading.gif') no-repeat;
background-size: contain;
opacity: 1;
margin: 0 1ex;
}
.btn-fullscreen {
padding: 15px;

View File

@ -6,7 +6,8 @@
*/
app.controller('NoteController', function($routeParams, $scope, NotesModel,
SaveQueue, note, debounce) {
SaveQueue, note, debounce,
$document) {
'use strict';
NotesModel.updateIfExists(note);
@ -16,16 +17,42 @@ app.controller('NoteController', function($routeParams, $scope, NotesModel,
$scope.isSaving = function () {
return SaveQueue.isSaving();
};
$scope.isManualSaving = function () {
return SaveQueue.isManualSaving();
};
$scope.updateTitle = function () {
$scope.note.title = $scope.note.content.split('\n')[0] ||
t('notes', 'New note');
};
$scope.save = debounce(function() {
$scope.onEdit = function() {
var note = $scope.note;
note.unsaved = true;
$scope.autoSave(note);
};
$scope.autoSave = debounce(function(note) {
SaveQueue.add(note);
}, 300);
}, 1000);
$scope.manualSave = function() {
var note = $scope.note;
note.error = false;
SaveQueue.addManual(note);
};
$document.unbind('keypress.notes.save');
$document.bind('keypress.notes.save', function(event) {
if(event.ctrlKey || event.metaKey) {
switch(String.fromCharCode(event.which).toLowerCase()) {
case 's':
event.preventDefault();
$scope.manualSave();
break;
}
}
});
$scope.toggleDistractionFree = function() {
function launchIntoFullscreen(element) {

View File

@ -7,7 +7,7 @@
// This is available by using ng-controller="NotesController" in your HTML
app.controller('NotesController', function($routeParams, $scope, $location,
Restangular, NotesModel) {
Restangular, NotesModel, $window) {
'use strict';
$scope.route = $routeParams;
@ -43,4 +43,15 @@ app.controller('NotesController', function($routeParams, $scope, $location,
});
};
$window.onbeforeunload = function() {
var notes = NotesModel.getAll();
for(var i=0; i<notes.length; i++) {
if(notes[i].unsaved) {
return t('notes', 'There are unsaved notes. Leaving ' +
'the page will discard all changes!');
}
}
return null;
};
});

View File

@ -23,7 +23,7 @@ app.directive('editor', ['$timeout',
$timeout(function() {
scope.$apply(function () {
scope.note.content = simplemde.value();
scope.save();
scope.onEdit();
scope.updateTitle();
});
});

View File

@ -1,26 +0,0 @@
/**
* Copyright (c) 2013, Bernhard Posselt <dev@bernhard-posselt.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING file.
*/
app.directive('notesIsSaving', function ($window) {
'use strict';
return {
restrict: 'A',
scope: {
'notesIsSaving': '='
},
link: function (scope) {
$window.onbeforeunload = function () {
if (scope.notesIsSaving) {
return t('notes', 'Note is currently saving. Leaving ' +
'the page will delete all changes!');
} else {
return null;
}
};
}
};
});

View File

@ -11,6 +11,7 @@ app.factory('SaveQueue', function($q) {
var SaveQueue = function () {
this._queue = {};
this._flushLock = false;
this._manualSaveActive = false;
};
SaveQueue.prototype = {
@ -18,6 +19,10 @@ app.factory('SaveQueue', function($q) {
this._queue[note.id] = note;
this._flush();
},
addManual: function (note) {
this._manualSaveActive = true;
this.add(note);
},
_flush: function () {
// if there are no changes dont execute the requests
var keys = Object.keys(this._queue);
@ -38,6 +43,7 @@ app.factory('SaveQueue', function($q) {
// attributes on the note
requests.push(note.put().then(
this._noteUpdateRequest.bind(null, note))
.catch(this._saveFailed.bind(null, note))
);
}
this._queue = {};
@ -47,16 +53,27 @@ app.factory('SaveQueue', function($q) {
$q.all(requests).then(function () {
self._flushLock = false;
self._flush();
self._manualSaveActive = false;
});
},
_noteUpdateRequest: function (note, response) {
note.error = false;
note.title = response.title;
note.modified = response.modified;
if(response.content === note.content) {
note.unsaved = false;
}
},
_saveFailed: function (note) {
note.error = true;
},
isSaving: function () {
return this._flushLock;
}
},
isManualSaving: function () {
return this._manualSaveActive;
},
};
return new SaveQueue();
});
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -51,6 +51,7 @@ style('notes', [
ng-class="{ active: note.id == route.noteId }">
<a href="#/notes/{{ note.id }}">
{{ note.title | noteTitle }}
<span ng-if="note.unsaved">*</span>
</a>
<span class="utils">
<button class="svg action icon-delete"

View File

@ -1,6 +1,9 @@
<textarea editor notes-timeout-change="save()" name="editor"></textarea>
<textarea editor notes-timeout-change="onEdit()" name="editor"></textarea>
<div class="note-meta">
<span class="note-word-count" ng-if="note.content.length > 0">{{note.content | wordCount}}</span>
<span class="note-unsaved" ng-if="note.unsaved" title="<?php p($l->t('The note has unsaved changes.')); ?>"><?php p($l->t('*')); ?></span>
<span class="note-error" ng-if="note.error" ng-click="manualSave()" title="<?php p($l->t('Click here to try again')); ?>"><?php p($l->t('Save failed!')); ?></span>
<span class="saving" ng-if="isManualSaving()" title="<?php p($l->t('The note is currently saved')); ?>"></span>
<span class="note-meta-right">
<button class="icon-fullscreen has-tooltip btn-fullscreen" notes-tooltip ng-click="toggleDistractionFree()"></button>
</span>