Fix error handling for save / manual save (#137)
This commit is contained in:
parent
7182d31907
commit
2eea48b05d
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
});
|
||||
|
|
|
@ -23,7 +23,7 @@ app.directive('editor', ['$timeout',
|
|||
$timeout(function() {
|
||||
scope.$apply(function () {
|
||||
scope.note.content = simplemde.value();
|
||||
scope.save();
|
||||
scope.onEdit();
|
||||
scope.updateTitle();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
|
@ -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
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue