merged master
This commit is contained in:
@@ -15,30 +15,9 @@ angular.module('app.frontend')
|
|||||||
bindToController: true,
|
bindToController: true,
|
||||||
|
|
||||||
link:function(scope, elem, attrs, ctrl) {
|
link:function(scope, elem, attrs, ctrl) {
|
||||||
|
|
||||||
var handler = function(event) {
|
|
||||||
if (event.ctrlKey || event.metaKey) {
|
|
||||||
switch (String.fromCharCode(event.which).toLowerCase()) {
|
|
||||||
case 'o':
|
|
||||||
event.preventDefault();
|
|
||||||
$timeout(function(){
|
|
||||||
ctrl.toggleFullScreen();
|
|
||||||
})
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('keydown', handler);
|
|
||||||
scope.$on('$destroy', function(){
|
|
||||||
window.removeEventListener('keydown', handler);
|
|
||||||
})
|
|
||||||
|
|
||||||
scope.$watch('ctrl.note', function(note, oldNote){
|
scope.$watch('ctrl.note', function(note, oldNote){
|
||||||
if(note) {
|
if(note) {
|
||||||
ctrl.setNote(note, oldNote);
|
ctrl.setNote(note, oldNote);
|
||||||
} else {
|
|
||||||
ctrl.note = {};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -47,27 +26,49 @@ angular.module('app.frontend')
|
|||||||
.controller('EditorCtrl', function ($sce, $timeout, authManager, $rootScope, extensionManager, syncManager, modelManager) {
|
.controller('EditorCtrl', function ($sce, $timeout, authManager, $rootScope, extensionManager, syncManager, modelManager) {
|
||||||
|
|
||||||
window.addEventListener("message", function(event){
|
window.addEventListener("message", function(event){
|
||||||
// console.log("App received message:", event);
|
|
||||||
if(event.data.status) {
|
if(event.data.status) {
|
||||||
this.postNoteToExternalEditor();
|
this.postNoteToExternalEditor();
|
||||||
} else {
|
} else {
|
||||||
var id = event.data.id;
|
var id = event.data.id;
|
||||||
var text = event.data.text;
|
var text = event.data.text;
|
||||||
if(this.note.uuid == id) {
|
var data = event.data.data;
|
||||||
|
|
||||||
|
if(this.note.uuid === id) {
|
||||||
this.note.text = text;
|
this.note.text = text;
|
||||||
|
if(data) {
|
||||||
|
var changesMade = this.customEditor.setData(id, data);
|
||||||
|
if(changesMade) {
|
||||||
|
this.customEditor.setDirty(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.changesMade();
|
this.changesMade();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.bind(this), false);
|
}.bind(this), false);
|
||||||
|
|
||||||
this.setNote = function(note, oldNote) {
|
this.setNote = function(note, oldNote) {
|
||||||
|
var currentEditor = this.customEditor;
|
||||||
|
this.customEditor = null;
|
||||||
this.showExtensions = false;
|
this.showExtensions = false;
|
||||||
this.showMenu = false;
|
this.showMenu = false;
|
||||||
this.loadTagsString();
|
this.loadTagsString();
|
||||||
|
|
||||||
if(note.editorUrl) {
|
var setEditor = function(editor) {
|
||||||
this.customEditor = this.editorForUrl(note.editorUrl);
|
this.customEditor = editor;
|
||||||
this.postNoteToExternalEditor();
|
this.postNoteToExternalEditor();
|
||||||
|
}.bind(this)
|
||||||
|
|
||||||
|
var editor = this.editorForNote(note);
|
||||||
|
if(editor) {
|
||||||
|
if(currentEditor !== editor) {
|
||||||
|
// switch after timeout, so that note data isnt posted to current editor
|
||||||
|
$timeout(function(){
|
||||||
|
setEditor(editor);
|
||||||
|
}.bind(this));
|
||||||
|
} else {
|
||||||
|
// switch immediately
|
||||||
|
setEditor(editor);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.customEditor = null;
|
this.customEditor = null;
|
||||||
}
|
}
|
||||||
@@ -87,23 +88,35 @@ angular.module('app.frontend')
|
|||||||
|
|
||||||
this.selectedEditor = function(editor) {
|
this.selectedEditor = function(editor) {
|
||||||
this.showEditorMenu = false;
|
this.showEditorMenu = false;
|
||||||
|
|
||||||
|
if(this.customEditor && editor !== this.customEditor) {
|
||||||
|
this.customEditor.removeItemAsRelationship(this.note);
|
||||||
|
this.customEditor.setDirty(true);
|
||||||
|
}
|
||||||
|
|
||||||
if(editor.default) {
|
if(editor.default) {
|
||||||
this.customEditor = null;
|
this.customEditor = null;
|
||||||
} else {
|
} else {
|
||||||
this.customEditor = editor;
|
this.customEditor = editor;
|
||||||
|
this.customEditor.addItemAsRelationship(this.note);
|
||||||
|
this.customEditor.setDirty(true);
|
||||||
}
|
}
|
||||||
this.note.editorUrl = editor.url;
|
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
|
|
||||||
this.editorForUrl = function(url) {
|
this.editorForNote = function(note) {
|
||||||
var editors = modelManager.itemsForContentType("SN|Editor");
|
var editors = modelManager.itemsForContentType("SN|Editor");
|
||||||
return editors.filter(function(editor){return editor.url == url})[0];
|
for(var editor of editors) {
|
||||||
|
if(_.includes(editor.notes, note)) {
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.postNoteToExternalEditor = function() {
|
this.postNoteToExternalEditor = function() {
|
||||||
var externalEditorElement = document.getElementById("editor-iframe");
|
var externalEditorElement = document.getElementById("editor-iframe");
|
||||||
if(externalEditorElement) {
|
if(externalEditorElement) {
|
||||||
externalEditorElement.contentWindow.postMessage({text: this.note.text, id: this.note.uuid}, '*');
|
externalEditorElement.contentWindow.postMessage({text: this.note.text, data: this.customEditor.dataForKey(this.note.uuid), id: this.note.uuid}, '*');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,6 +227,11 @@ angular.module('app.frontend')
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clickedEditNote = function() {
|
||||||
|
this.editorMode = 'edit';
|
||||||
|
this.focusEditor(100);
|
||||||
|
}
|
||||||
|
|
||||||
/* Tags */
|
/* Tags */
|
||||||
|
|
||||||
this.loadTagsString = function() {
|
this.loadTagsString = function() {
|
||||||
|
|||||||
@@ -1,7 +1,31 @@
|
|||||||
angular.module('app.frontend')
|
angular.module('app.frontend')
|
||||||
.controller('HomeCtrl', function ($scope, $rootScope, $timeout, modelManager, syncManager, authManager) {
|
.controller('HomeCtrl', function ($scope, $stateParams, $rootScope, $timeout, modelManager, syncManager, authManager) {
|
||||||
|
|
||||||
|
function autoSignInFromParams() {
|
||||||
|
if(!authManager.offline()) {
|
||||||
|
// check if current account
|
||||||
|
if(syncManager.serverURL == $stateParams.server && authManager.user.email == $stateParams.email) {
|
||||||
|
// already signed in, return
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// sign out
|
||||||
|
syncManager.destroyLocalData(function(){
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authManager.login($stateParams.server, $stateParams.email, $stateParams.pw, function(response){
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($stateParams.server && $stateParams.email) {
|
||||||
|
autoSignInFromParams();
|
||||||
|
}
|
||||||
|
|
||||||
syncManager.loadLocalItems(function(items) {
|
syncManager.loadLocalItems(function(items) {
|
||||||
|
$scope.allTag.didLoad = true;
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
|
|
||||||
syncManager.sync(null);
|
syncManager.sync(null);
|
||||||
@@ -11,7 +35,9 @@ angular.module('app.frontend')
|
|||||||
}, 30000);
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.allTag = new Tag({all: true});
|
var allTag = new Tag({all: true});
|
||||||
|
allTag.needsLoad = true;
|
||||||
|
$scope.allTag = allTag;
|
||||||
$scope.allTag.title = "All";
|
$scope.allTag.title = "All";
|
||||||
$scope.tags = modelManager.tags;
|
$scope.tags = modelManager.tags;
|
||||||
$scope.allTag.notes = modelManager.notes;
|
$scope.allTag.notes = modelManager.notes;
|
||||||
@@ -127,6 +153,12 @@ angular.module('app.frontend')
|
|||||||
this.$apply(fn);
|
this.$apply(fn);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.notifyDelete = function() {
|
||||||
|
$timeout(function() {
|
||||||
|
$rootScope.$broadcast("noteDeleted");
|
||||||
|
}.bind(this), 0);
|
||||||
|
}
|
||||||
|
|
||||||
$scope.deleteNote = function(note) {
|
$scope.deleteNote = function(note) {
|
||||||
|
|
||||||
modelManager.setItemToBeDeleted(note);
|
modelManager.setItemToBeDeleted(note);
|
||||||
@@ -137,6 +169,7 @@ angular.module('app.frontend')
|
|||||||
|
|
||||||
if(note.dummy) {
|
if(note.dummy) {
|
||||||
modelManager.removeItemLocally(note);
|
modelManager.removeItemLocally(note);
|
||||||
|
$scope.notifyDelete();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,8 +177,11 @@ angular.module('app.frontend')
|
|||||||
if(authManager.offline()) {
|
if(authManager.offline()) {
|
||||||
// when deleting items while ofline, we need to explictly tell angular to refresh UI
|
// when deleting items while ofline, we need to explictly tell angular to refresh UI
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
|
$scope.notifyDelete();
|
||||||
$scope.safeApply();
|
$scope.safeApply();
|
||||||
}, 50);
|
}, 50);
|
||||||
|
} else {
|
||||||
|
$scope.notifyDelete();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ angular.module('app.frontend')
|
|||||||
scope: {
|
scope: {
|
||||||
addNew: "&",
|
addNew: "&",
|
||||||
selectionMade: "&",
|
selectionMade: "&",
|
||||||
remove: "&",
|
|
||||||
tag: "=",
|
tag: "=",
|
||||||
removeTag: "&"
|
removeTag: "&"
|
||||||
},
|
},
|
||||||
@@ -18,7 +17,16 @@ angular.module('app.frontend')
|
|||||||
link:function(scope, elem, attrs, ctrl) {
|
link:function(scope, elem, attrs, ctrl) {
|
||||||
scope.$watch('ctrl.tag', function(tag, oldTag){
|
scope.$watch('ctrl.tag', function(tag, oldTag){
|
||||||
if(tag) {
|
if(tag) {
|
||||||
ctrl.tagDidChange(tag, oldTag);
|
if(tag.needsLoad) {
|
||||||
|
scope.$watch('ctrl.tag.didLoad', function(didLoad){
|
||||||
|
if(didLoad) {
|
||||||
|
tag.needsLoad = false;
|
||||||
|
ctrl.tagDidChange(tag, oldTag);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ctrl.tagDidChange(tag, oldTag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -32,7 +40,9 @@ angular.module('app.frontend')
|
|||||||
this.showMenu = false;
|
this.showMenu = false;
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
|
|
||||||
var isFirstLoad = true;
|
$rootScope.$on("noteDeleted", function() {
|
||||||
|
this.selectFirstNote(false);
|
||||||
|
}.bind(this))
|
||||||
|
|
||||||
this.notesToDisplay = 20;
|
this.notesToDisplay = 20;
|
||||||
this.paginate = function() {
|
this.paginate = function() {
|
||||||
@@ -47,20 +57,16 @@ angular.module('app.frontend')
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.noteFilter.text = "";
|
this.noteFilter.text = "";
|
||||||
|
this.setNotes(tag.notes);
|
||||||
|
}
|
||||||
|
|
||||||
tag.notes.forEach(function(note){
|
this.setNotes = function(notes) {
|
||||||
|
notes.forEach(function(note){
|
||||||
note.visible = true;
|
note.visible = true;
|
||||||
})
|
})
|
||||||
this.selectFirstNote(false);
|
|
||||||
|
|
||||||
if(isFirstLoad) {
|
var createNew = notes.length == 0;
|
||||||
$timeout(function(){
|
this.selectFirstNote(createNew);
|
||||||
this.createNewNote();
|
|
||||||
isFirstLoad = false;
|
|
||||||
}.bind(this))
|
|
||||||
} else if(tag.notes.length == 0) {
|
|
||||||
this.createNewNote();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selectedTagDelete = function() {
|
this.selectedTagDelete = function() {
|
||||||
@@ -69,7 +75,7 @@ angular.module('app.frontend')
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.selectFirstNote = function(createNew) {
|
this.selectFirstNote = function(createNew) {
|
||||||
var visibleNotes = this.tag.notes.filter(function(note){
|
var visibleNotes = this.sortedNotes.filter(function(note){
|
||||||
return note.visible;
|
return note.visible;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,24 +2,70 @@ class Editor extends Item {
|
|||||||
|
|
||||||
constructor(json_obj) {
|
constructor(json_obj) {
|
||||||
super(json_obj);
|
super(json_obj);
|
||||||
|
if(!this.notes) {
|
||||||
|
this.notes = [];
|
||||||
|
}
|
||||||
|
if(!this.data) {
|
||||||
|
this.data = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mapContentToLocalProperties(contentObject) {
|
mapContentToLocalProperties(contentObject) {
|
||||||
super.mapContentToLocalProperties(contentObject)
|
super.mapContentToLocalProperties(contentObject)
|
||||||
this.url = contentObject.url;
|
this.url = contentObject.url;
|
||||||
this.name = contentObject.name;
|
this.name = contentObject.name;
|
||||||
|
this.data = contentObject.data || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
structureParams() {
|
structureParams() {
|
||||||
var params = {
|
var params = {
|
||||||
url: this.url,
|
url: this.url,
|
||||||
name: this.name
|
name: this.name,
|
||||||
|
data: this.data
|
||||||
};
|
};
|
||||||
|
|
||||||
_.merge(params, super.structureParams());
|
_.merge(params, super.structureParams());
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
referenceParams() {
|
||||||
|
var references = _.map(this.notes, function(note){
|
||||||
|
return {uuid: note.uuid, content_type: note.content_type};
|
||||||
|
})
|
||||||
|
|
||||||
|
return references;
|
||||||
|
}
|
||||||
|
|
||||||
|
addItemAsRelationship(item) {
|
||||||
|
if(item.content_type == "Note") {
|
||||||
|
if(!_.find(this.notes, item)) {
|
||||||
|
this.notes.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.addItemAsRelationship(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItemAsRelationship(item) {
|
||||||
|
if(item.content_type == "Note") {
|
||||||
|
_.pull(this.notes, item);
|
||||||
|
}
|
||||||
|
super.removeItemAsRelationship(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAllRelationships() {
|
||||||
|
super.removeAllRelationships();
|
||||||
|
this.notes = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
locallyClearAllReferences() {
|
||||||
|
super.locallyClearAllReferences();
|
||||||
|
this.notes = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
allReferencedObjects() {
|
||||||
|
return this.notes;
|
||||||
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return {uuid: this.uuid}
|
return {uuid: this.uuid}
|
||||||
}
|
}
|
||||||
@@ -27,4 +73,17 @@ class Editor extends Item {
|
|||||||
get content_type() {
|
get content_type() {
|
||||||
return "SN|Editor";
|
return "SN|Editor";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setData(key, value) {
|
||||||
|
var dataHasChanged = JSON.stringify(this.data[key]) !== JSON.stringify(value);
|
||||||
|
if(dataHasChanged) {
|
||||||
|
this.data[key] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataForKey(key) {
|
||||||
|
return this.data[key] || {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class Note extends Item {
|
|||||||
_.pull(tag.notes, this);
|
_.pull(tag.notes, this);
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
this.tags = [];
|
this.tags = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
isBeingRemovedLocally() {
|
isBeingRemovedLocally() {
|
||||||
this.tags.forEach(function(tag){
|
this.tags.forEach(function(tag){
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class ItemParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
paramsForLocalStorage() {
|
paramsForLocalStorage() {
|
||||||
this.additionalFields = ["updated_at", "dirty", "editorUrl"];
|
this.additionalFields = ["updated_at", "dirty"];
|
||||||
this.forExportFile = true;
|
this.forExportFile = true;
|
||||||
return this.__params();
|
return this.__params();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ angular.module('app.frontend')
|
|||||||
})
|
})
|
||||||
|
|
||||||
.state('home', {
|
.state('home', {
|
||||||
url: '/',
|
url: '/?server&email&pw',
|
||||||
parent: 'base',
|
parent: 'base',
|
||||||
views: {
|
views: {
|
||||||
'content@' : {
|
'content@' : {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ angular.module('app.frontend')
|
|||||||
callback(response);
|
callback(response);
|
||||||
}.bind(this), function(response){
|
}.bind(this), function(response){
|
||||||
console.error("Error logging in", response);
|
console.error("Error logging in", response);
|
||||||
callback(null);
|
callback(response);
|
||||||
})
|
})
|
||||||
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
@@ -106,8 +106,8 @@ angular.module('app.frontend')
|
|||||||
callback(response);
|
callback(response);
|
||||||
}.bind(this), function(response){
|
}.bind(this), function(response){
|
||||||
console.error("Registration error", response);
|
console.error("Registration error", response);
|
||||||
callback(null);
|
callback(response);
|
||||||
})
|
}.bind(this))
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ angular.module('app.frontend')
|
|||||||
this.handleAuthResponse(response, email, null, authParams, keys.mk, keys.pw);
|
this.handleAuthResponse(response, email, null, authParams, keys.mk, keys.pw);
|
||||||
callback(response);
|
callback(response);
|
||||||
}.bind(this), function(response){
|
}.bind(this), function(response){
|
||||||
var error = response.data;
|
var error = response;
|
||||||
if(!error) {
|
if(!error) {
|
||||||
error = {message: "Something went wrong while changing your password. Your password was not changed. Please try again."}
|
error = {message: "Something went wrong while changing your password. Your password was not changed. Please try again."}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ class AccountMenu {
|
|||||||
this.scope = {};
|
this.scope = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
controller($scope, authManager, modelManager, syncManager, $timeout) {
|
controller($scope, authManager, modelManager, syncManager, dbManager, $timeout) {
|
||||||
'ngInject';
|
'ngInject';
|
||||||
|
|
||||||
$scope.formData = {url: syncManager.serverURL};
|
$scope.formData = {mergeLocal: true, url: syncManager.serverURL};
|
||||||
$scope.user = authManager.user;
|
$scope.user = authManager.user;
|
||||||
$scope.server = syncManager.serverURL;
|
$scope.server = syncManager.serverURL;
|
||||||
|
|
||||||
@@ -82,7 +82,6 @@ class AccountMenu {
|
|||||||
|
|
||||||
$scope.loginSubmitPressed = function() {
|
$scope.loginSubmitPressed = function() {
|
||||||
$scope.formData.status = "Generating Login Keys...";
|
$scope.formData.status = "Generating Login Keys...";
|
||||||
console.log("logging in with url", $scope.formData.url);
|
|
||||||
$timeout(function(){
|
$timeout(function(){
|
||||||
authManager.login($scope.formData.url, $scope.formData.email, $scope.formData.user_password, function(response){
|
authManager.login($scope.formData.url, $scope.formData.email, $scope.formData.user_password, function(response){
|
||||||
if(!response || response.error) {
|
if(!response || response.error) {
|
||||||
@@ -99,6 +98,11 @@ class AccountMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$scope.submitRegistrationForm = function() {
|
$scope.submitRegistrationForm = function() {
|
||||||
|
var confirmation = prompt("Please confirm your password. Note that because your notes are encrypted using your password, Standard Notes does not have a password reset option. You cannot forget your password.")
|
||||||
|
if(confirmation !== $scope.formData.user_password) {
|
||||||
|
alert("The two passwords you entered do not match. Please try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
$scope.formData.status = "Generating Account Keys...";
|
$scope.formData.status = "Generating Account Keys...";
|
||||||
|
|
||||||
$timeout(function(){
|
$timeout(function(){
|
||||||
@@ -114,10 +118,32 @@ class AccountMenu {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.localNotesCount = function() {
|
||||||
|
return modelManager.filteredNotes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.mergeLocalChanged = function() {
|
||||||
|
if(!$scope.formData.mergeLocal) {
|
||||||
|
if(!confirm("Unchecking this option means any of the notes you have written while you were signed out will be deleted. Are you sure you want to discard these notes?")) {
|
||||||
|
$scope.formData.mergeLocal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$scope.onAuthSuccess = function() {
|
$scope.onAuthSuccess = function() {
|
||||||
syncManager.markAllItemsDirtyAndSaveOffline(function(){
|
var block = function() {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if($scope.formData.mergeLocal) {
|
||||||
|
syncManager.markAllItemsDirtyAndSaveOffline(function(){
|
||||||
|
block();
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
dbManager.clearAllItems(function(){
|
||||||
|
block();
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.destroyLocalData = function() {
|
$scope.destroyLocalData = function() {
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ class ModelManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mapResponseItemsToLocalModelsOmittingFields(items, omitFields) {
|
mapResponseItemsToLocalModelsOmittingFields(items, omitFields) {
|
||||||
var models = [];
|
var models = [], processedObjects = [];
|
||||||
|
|
||||||
|
// first loop should add and process items
|
||||||
for (var json_obj of items) {
|
for (var json_obj of items) {
|
||||||
json_obj = _.omit(json_obj, omitFields || [])
|
json_obj = _.omit(json_obj, omitFields || [])
|
||||||
var item = this.findItem(json_obj["uuid"]);
|
var item = this.findItem(json_obj["uuid"]);
|
||||||
@@ -80,11 +82,16 @@ class ModelManager {
|
|||||||
|
|
||||||
this.addItem(item);
|
this.addItem(item);
|
||||||
|
|
||||||
if(json_obj.content) {
|
|
||||||
this.resolveReferencesForItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
models.push(item);
|
models.push(item);
|
||||||
|
processedObjects.push(json_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// second loop should process references
|
||||||
|
for (var index in processedObjects) {
|
||||||
|
var json_obj = processedObjects[index];
|
||||||
|
if(json_obj.content) {
|
||||||
|
this.resolveReferencesForItem(models[index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.notifySyncObserversOfModels(models);
|
this.notifySyncObserversOfModels(models);
|
||||||
@@ -174,6 +181,7 @@ class ModelManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for(var reference of contentObject.references) {
|
for(var reference of contentObject.references) {
|
||||||
var referencedItem = this.findItem(reference.uuid);
|
var referencedItem = this.findItem(reference.uuid);
|
||||||
if(referencedItem) {
|
if(referencedItem) {
|
||||||
|
|||||||
@@ -187,7 +187,6 @@ class SyncManager {
|
|||||||
var saved = this.handleItemsResponse(response.saved_items, omitFields);
|
var saved = this.handleItemsResponse(response.saved_items, omitFields);
|
||||||
|
|
||||||
this.handleUnsavedItemsResponse(response.unsaved)
|
this.handleUnsavedItemsResponse(response.unsaved)
|
||||||
|
|
||||||
this.writeItemsToLocalStorage(saved, false, null);
|
this.writeItemsToLocalStorage(saved, false, null);
|
||||||
this.writeItemsToLocalStorage(retrieved, false, null);
|
this.writeItemsToLocalStorage(retrieved, false, null);
|
||||||
|
|
||||||
@@ -213,7 +212,7 @@ class SyncManager {
|
|||||||
|
|
||||||
}.bind(this), function(response){
|
}.bind(this), function(response){
|
||||||
console.log("Sync error: ", response);
|
console.log("Sync error: ", response);
|
||||||
var error = response.data ? response.data.error : {message: "Could not connect to server."};
|
var error = response ? response.error : {message: "Could not connect to server."};
|
||||||
|
|
||||||
this.syncStatus.syncOpInProgress = false;
|
this.syncStatus.syncOpInProgress = false;
|
||||||
this.syncStatus.error = error;
|
this.syncStatus.error = error;
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
%input.form-control{:name => 'server', :placeholder => 'Server URL', :required => true, :type => 'text', 'ng-model' => 'formData.url'}
|
%input.form-control{:name => 'server', :placeholder => 'Server URL', :required => true, :type => 'text', 'ng-model' => 'formData.url'}
|
||||||
%input.form-control{:autofocus => 'autofocus', :name => 'email', :placeholder => 'Email', :required => true, :type => 'email', 'ng-model' => 'formData.email'}
|
%input.form-control{:autofocus => 'autofocus', :name => 'email', :placeholder => 'Email', :required => true, :type => 'email', 'ng-model' => 'formData.email'}
|
||||||
%input.form-control{:placeholder => 'Password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'formData.user_password'}
|
%input.form-control{:placeholder => 'Password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'formData.user_password'}
|
||||||
|
.checkbox{"ng-if" => "localNotesCount() > 0"}
|
||||||
|
%label
|
||||||
|
%input{"type" => "checkbox", "ng-model" => "formData.mergeLocal", "ng-bind" => "true", "ng-change" => "mergeLocalChanged()"}
|
||||||
|
Merge local notes ({{localNotesCount()}} notes)
|
||||||
|
|
||||||
%div{"ng-if" => "!formData.status"}
|
%div{"ng-if" => "!formData.status"}
|
||||||
%button.btn.dark-button.half-button{"ng-click" => "loginSubmitPressed()", "data-style" => "expand-right", "data-size" => "s", "state" => "buttonState"}
|
%button.btn.dark-button.half-button{"ng-click" => "loginSubmitPressed()", "data-style" => "expand-right", "data-size" => "s", "state" => "buttonState"}
|
||||||
@@ -94,4 +98,4 @@
|
|||||||
|
|
||||||
.spinner.mt-10{"ng-if" => "importData.loading"}
|
.spinner.mt-10{"ng-if" => "importData.loading"}
|
||||||
|
|
||||||
%a.block.mt-25.red{"ng-click" => "destroyLocalData()"} Destroy all local data
|
%a.block.mt-25.red{"ng-click" => "destroyLocalData()"} {{ user ? "Sign out and clear local data" : "Clear all local data" }}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.section.editor{"ng-class" => "{'fullscreen' : ctrl.fullscreen}"}
|
.section.editor{"ng-class" => "{'fullscreen' : ctrl.fullscreen}"}
|
||||||
.section-title-bar.editor-heading{"ng-class" => "{'fullscreen' : ctrl.fullscreen }"}
|
.section-title-bar.editor-heading{"ng-if" => "ctrl.note", "ng-class" => "{'fullscreen' : ctrl.fullscreen }"}
|
||||||
.title
|
.title
|
||||||
%input.input#note-title-editor{"ng-model" => "ctrl.note.title", "ng-keyup" => "$event.keyCode == 13 && ctrl.saveTitle($event)",
|
%input.input#note-title-editor{"ng-model" => "ctrl.note.title", "ng-keyup" => "$event.keyCode == 13 && ctrl.saveTitle($event)",
|
||||||
"ng-change" => "ctrl.nameChanged()", "ng-focus" => "ctrl.onNameFocus()",
|
"ng-change" => "ctrl.nameChanged()", "ng-focus" => "ctrl.onNameFocus()",
|
||||||
@@ -8,20 +8,19 @@
|
|||||||
.tags
|
.tags
|
||||||
%input.tags-input{"type" => "text", "ng-keyup" => "$event.keyCode == 13 && $event.target.blur();",
|
%input.tags-input{"type" => "text", "ng-keyup" => "$event.keyCode == 13 && $event.target.blur();",
|
||||||
"ng-model" => "ctrl.tagsString", "placeholder" => "#tags", "ng-blur" => "ctrl.updateTagsFromTagsString($event, ctrl.tagsString)"}
|
"ng-model" => "ctrl.tagsString", "placeholder" => "#tags", "ng-blur" => "ctrl.updateTagsFromTagsString($event, ctrl.tagsString)"}
|
||||||
.section-menu
|
.section-menu{"ng-if" => "ctrl.note"}
|
||||||
%ul.nav
|
%ul.nav
|
||||||
%li.dropdown.pull-left.mr-10{"click-outside" => "ctrl.showMenu = false;", "is-open" => "ctrl.showMenu"}
|
%li.dropdown.pull-left.mr-10{"click-outside" => "ctrl.showMenu = false;", "is-open" => "ctrl.showMenu"}
|
||||||
%a.dropdown-toggle{"ng-click" => "ctrl.showMenu = !ctrl.showMenu; ctrl.showExtensions = false;"}
|
%a.dropdown-toggle{"ng-click" => "ctrl.showMenu = !ctrl.showMenu; ctrl.showExtensions = false;"}
|
||||||
File
|
Menu
|
||||||
%span.caret
|
%span.caret
|
||||||
%span.sr-only
|
%span.sr-only
|
||||||
|
|
||||||
%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark{"ng-if" => "ctrl.showMenu"}
|
%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark{"ng-if" => "ctrl.showMenu"}
|
||||||
%li{"ng-click" => "ctrl.selectedMenuItem(); ctrl.toggleFullScreen()"}
|
%li{"ng-click" => "ctrl.selectedMenuItem(); ctrl.toggleFullScreen()"}
|
||||||
.text Toggle Fullscreen
|
.text Toggle Fullscreen
|
||||||
.shortcut Cmd + O
|
|
||||||
%li{"ng-click" => "ctrl.deleteNote()"}
|
%li{"ng-click" => "ctrl.deleteNote()"}
|
||||||
.text Delete
|
.text Delete Note
|
||||||
|
|
||||||
%li.sep
|
%li.sep
|
||||||
%li.dropdown.pull-left.mr-10{"click-outside" => "ctrl.showEditorMenu = false;", "is-open" => "ctrl.showEditorMenu"}
|
%li.dropdown.pull-left.mr-10{"click-outside" => "ctrl.showEditorMenu = false;", "is-open" => "ctrl.showEditorMenu"}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"tags" => "tags"}
|
"tags" => "tags"}
|
||||||
|
|
||||||
%notes-section{"remove-tag" => "notesRemoveTag", "add-new" => "notesAddNew", "selection-made" => "notesSelectionMade",
|
%notes-section{"remove-tag" => "notesRemoveTag", "add-new" => "notesAddNew", "selection-made" => "notesSelectionMade",
|
||||||
"tag" => "selectedTag", "remove" => "deleteNote"}
|
"tag" => "selectedTag"}
|
||||||
|
|
||||||
%editor-section{"ng-if" => "selectedNote", "note" => "selectedNote", "remove" => "deleteNote", "save" => "saveNote", "update-tags" => "updateTagsForNote"}
|
%editor-section{"note" => "selectedNote", "remove" => "deleteNote", "save" => "saveNote", "update-tags" => "updateTagsForNote"}
|
||||||
|
|
||||||
%header
|
%header
|
||||||
|
|||||||
@@ -10,13 +10,11 @@
|
|||||||
%ul.nav.nav-pills
|
%ul.nav.nav-pills
|
||||||
%li.dropdown
|
%li.dropdown
|
||||||
%a.dropdown-toggle{"ng-click" => "ctrl.showMenu = !ctrl.showMenu"}
|
%a.dropdown-toggle{"ng-click" => "ctrl.showMenu = !ctrl.showMenu"}
|
||||||
Tag options
|
Menu
|
||||||
%span.caret
|
%span.caret
|
||||||
%span.sr-only
|
%span.sr-only
|
||||||
|
|
||||||
%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark{"ng-if" => "ctrl.showMenu"}
|
%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark{"ng-if" => "ctrl.showMenu"}
|
||||||
%li
|
|
||||||
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagDelete()"} Delete Tag
|
|
||||||
%li
|
%li
|
||||||
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedSortByCreated()"}
|
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedSortByCreated()"}
|
||||||
%span.top.mt-5.mr-5{"ng-if" => "ctrl.sortBy == 'created_at'"} ✓
|
%span.top.mt-5.mr-5{"ng-if" => "ctrl.sortBy == 'created_at'"} ✓
|
||||||
@@ -25,10 +23,12 @@
|
|||||||
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedSortByUpdated()"}
|
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedSortByUpdated()"}
|
||||||
%span.top.mt-5.mr-5{"ng-if" => "ctrl.sortBy == 'updated_at'"} ✓
|
%span.top.mt-5.mr-5{"ng-if" => "ctrl.sortBy == 'updated_at'"} ✓
|
||||||
Sort by date updated
|
Sort by date updated
|
||||||
|
%li
|
||||||
|
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagDelete()"} Delete Tag
|
||||||
|
|
||||||
.scrollable
|
.scrollable
|
||||||
.infinite-scroll{"infinite-scroll" => "ctrl.paginate()", "can-load" => "true", "threshold" => "200"}
|
.infinite-scroll{"infinite-scroll" => "ctrl.paginate()", "can-load" => "true", "threshold" => "200"}
|
||||||
.note{"ng-repeat" => "note in ctrl.tag.notes | filter: ctrl.filterNotes | orderBy: ctrl.sortBy:true | limitTo:ctrl.notesToDisplay",
|
.note{"ng-repeat" => "note in (ctrl.sortedNotes = (ctrl.tag.notes | filter: ctrl.filterNotes | orderBy: ctrl.sortBy:true | limitTo:ctrl.notesToDisplay))",
|
||||||
"ng-click" => "ctrl.selectNote(note)", "ng-class" => "{'selected' : ctrl.selectedNote == note}"}
|
"ng-click" => "ctrl.selectNote(note)", "ng-class" => "{'selected' : ctrl.selectedNote == note}"}
|
||||||
.name{"ng-if" => "note.title"}
|
.name{"ng-if" => "note.title"}
|
||||||
{{note.title}}
|
{{note.title}}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
# Prevent CSRF attacks by raising an exception.
|
|
||||||
# For APIs, you may want to use :null_session instead.
|
|
||||||
|
|
||||||
protect_from_forgery with: :null_session
|
protect_from_forgery with: :null_session
|
||||||
after_action :set_csrf_cookie
|
after_action :set_csrf_cookie
|
||||||
|
|
||||||
|
after_action :allow_iframe
|
||||||
|
|
||||||
layout :false
|
layout :false
|
||||||
|
|
||||||
def frontend
|
def frontend
|
||||||
@@ -13,8 +13,13 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
rescue_from ActionView::MissingTemplate do |exception|
|
rescue_from ActionView::MissingTemplate do |exception|
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
def allow_iframe
|
||||||
|
response.headers.except! 'X-Frame-Options'
|
||||||
|
end
|
||||||
|
|
||||||
def set_app_domain
|
def set_app_domain
|
||||||
@appDomain = request.domain
|
@appDomain = request.domain
|
||||||
@appDomain << ':' + request.port.to_s unless request.port.blank?
|
@appDomain << ':' + request.port.to_s unless request.port.blank?
|
||||||
|
|||||||
Reference in New Issue
Block a user