api format, css, auth errors
This commit is contained in:
@@ -75,8 +75,8 @@ module.exports = function(grunt) {
|
|||||||
'app/assets/javascripts/app/frontend/*.js',
|
'app/assets/javascripts/app/frontend/*.js',
|
||||||
'app/assets/javascripts/app/frontend/controllers/*.js',
|
'app/assets/javascripts/app/frontend/controllers/*.js',
|
||||||
'app/assets/javascripts/app/frontend/models/**/*.js',
|
'app/assets/javascripts/app/frontend/models/**/*.js',
|
||||||
'app/assets/javascripts/app/services/*.js',
|
'app/assets/javascripts/app/services/**/*.js',
|
||||||
'app/assets/javascripts/app/services/directives/*.js',
|
// 'app/assets/javascripts/app/services/directives/*.js',
|
||||||
],
|
],
|
||||||
dest: 'vendor/assets/javascripts/app.js',
|
dest: 'vendor/assets/javascripts/app.js',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ angular.module('app.frontend', [
|
|||||||
RestangularProvider.setDefaultHeaders({"Content-Type": "application/json"});
|
RestangularProvider.setDefaultHeaders({"Content-Type": "application/json"});
|
||||||
|
|
||||||
var url = apiControllerProvider.defaultServerURL();
|
var url = apiControllerProvider.defaultServerURL();
|
||||||
RestangularProvider.setBaseUrl(url);
|
RestangularProvider.setBaseUrl(url + "/api");
|
||||||
|
|
||||||
RestangularProvider.setFullRequestInterceptor(function(element, operation, route, url, headers, params, httpConfig) {
|
RestangularProvider.setFullRequestInterceptor(function(element, operation, route, url, headers, params, httpConfig) {
|
||||||
var token = localStorage.getItem("jwt");
|
var token = localStorage.getItem("jwt");
|
||||||
|
|||||||
@@ -73,9 +73,10 @@ angular.module('app.frontend')
|
|||||||
this.loginData.status = "Generating Login Keys...";
|
this.loginData.status = "Generating Login Keys...";
|
||||||
$timeout(function(){
|
$timeout(function(){
|
||||||
apiController.login(this.loginData.email, this.loginData.user_password, function(response){
|
apiController.login(this.loginData.email, this.loginData.user_password, function(response){
|
||||||
if(response.errors) {
|
if(!response || response.error) {
|
||||||
console.log("login error", response.errors);
|
var error = response ? response.error : {message: "An unknown error occured."}
|
||||||
this.loginData.status = response.errors[0];
|
this.loginData.status = null;
|
||||||
|
alert(error.message);
|
||||||
} else {
|
} else {
|
||||||
this.onAuthSuccess(response.user);
|
this.onAuthSuccess(response.user);
|
||||||
}
|
}
|
||||||
@@ -88,8 +89,10 @@ angular.module('app.frontend')
|
|||||||
|
|
||||||
$timeout(function(){
|
$timeout(function(){
|
||||||
apiController.register(this.loginData.email, this.loginData.user_password, function(response){
|
apiController.register(this.loginData.email, this.loginData.user_password, function(response){
|
||||||
if(response.errors) {
|
if(!response || response.error) {
|
||||||
this.loginData.status = response.errors[0];
|
var error = response ? response.error : {message: "An unknown error occured."}
|
||||||
|
this.loginData.status = null;
|
||||||
|
alert(error.message);
|
||||||
} else {
|
} else {
|
||||||
this.onAuthSuccess(response.user);
|
this.onAuthSuccess(response.user);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ angular.module('app.frontend')
|
|||||||
$rootScope.title = "Notes — Standard Notes";
|
$rootScope.title = "Notes — Standard Notes";
|
||||||
onUserSet();
|
onUserSet();
|
||||||
} else {
|
} else {
|
||||||
$scope.defaultUser = new User(apiController.localUser());
|
$scope.defaultUser = new User(apiController.loadLocalItemsAndUser());
|
||||||
onUserSet();
|
onUserSet();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -141,7 +141,7 @@ angular.module('app.frontend')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$scope.headerLogout = function() {
|
$scope.headerLogout = function() {
|
||||||
$scope.defaultUser = apiController.localUser();
|
$scope.defaultUser = apiController.loadLocalItemsAndUser();
|
||||||
$scope.tags = $scope.defaultUser.tags;
|
$scope.tags = $scope.defaultUser.tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,14 @@ class Item {
|
|||||||
|
|
||||||
_.merge(this, json_obj);
|
_.merge(this, json_obj);
|
||||||
|
|
||||||
|
if(this.created_at) {
|
||||||
|
this.created_at = new Date(this.created_at);
|
||||||
|
this.updated_at = new Date(this.updated_at);
|
||||||
|
} else {
|
||||||
|
this.created_at = new Date();
|
||||||
|
this.updated_at = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
if(!this.uuid) {
|
if(!this.uuid) {
|
||||||
this.uuid = Neeto.crypto.generateUUID();
|
this.uuid = Neeto.crypto.generateUUID();
|
||||||
}
|
}
|
||||||
@@ -43,6 +51,12 @@ class Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static sortItemsByDate(items) {
|
||||||
|
items.sort(function(a,b){
|
||||||
|
return new Date(b.created_at) - new Date(a.created_at);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
addReference(reference) {
|
addReference(reference) {
|
||||||
this.content.references.push(reference);
|
this.content.references.push(reference);
|
||||||
this.content.references = _.uniq(this.content.references);
|
this.content.references = _.uniq(this.content.references);
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ angular.module('app.frontend')
|
|||||||
request.get({email: email}).then(function(response){
|
request.get({email: email}).then(function(response){
|
||||||
callback(response.plain());
|
callback(response.plain());
|
||||||
})
|
})
|
||||||
|
.catch(function(response){
|
||||||
|
console.log("Error getting current user", response);
|
||||||
|
callback(response.data);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getCurrentUser = function(callback) {
|
this.getCurrentUser = function(callback) {
|
||||||
@@ -77,22 +81,32 @@ angular.module('app.frontend')
|
|||||||
var user = _.omit(plain, ["items"]);
|
var user = _.omit(plain, ["items"]);
|
||||||
callback(user, items);
|
callback(user, items);
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
.catch(function(error){
|
.catch(function(response){
|
||||||
console.log("Error getting current user", error);
|
console.log("Error getting current user", response);
|
||||||
callback(null);
|
callback(response.data);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.login = function(email, password, callback) {
|
this.login = function(email, password, callback) {
|
||||||
this.getAuthParamsForEmail(email, function(authParams){
|
this.getAuthParamsForEmail(email, function(authParams){
|
||||||
|
if(!authParams) {
|
||||||
|
callback(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({email: email, password: password}, authParams), function(keys){
|
Neeto.crypto.computeEncryptionKeysForUser(_.merge({email: email, password: password}, authParams), function(keys){
|
||||||
this.setMk(keys.mk);
|
this.setMk(keys.mk);
|
||||||
var request = Restangular.one("auth/sign_in");
|
var request = Restangular.one("auth/sign_in");
|
||||||
request.user = {password: keys.pw, email: email};
|
console.log("sending pw", keys.pw);
|
||||||
|
var params = {password: keys.pw, email: email};
|
||||||
|
_.merge(request, params);
|
||||||
request.post().then(function(response){
|
request.post().then(function(response){
|
||||||
localStorage.setItem("jwt", response.token);
|
localStorage.setItem("jwt", response.token);
|
||||||
callback(response);
|
callback(response);
|
||||||
})
|
})
|
||||||
|
.catch(function(response){
|
||||||
|
console.log(response.data);
|
||||||
|
callback(response.data);
|
||||||
|
})
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
}
|
}
|
||||||
@@ -102,16 +116,25 @@ angular.module('app.frontend')
|
|||||||
this.setMk(keys.mk);
|
this.setMk(keys.mk);
|
||||||
keys.mk = null;
|
keys.mk = null;
|
||||||
var request = Restangular.one("auth");
|
var request = Restangular.one("auth");
|
||||||
request.user = _.merge({password: keys.pw, email: email}, keys);
|
var params = _.merge({password: keys.pw, email: email}, keys);
|
||||||
|
_.merge(request, params);
|
||||||
request.post().then(function(response){
|
request.post().then(function(response){
|
||||||
localStorage.setItem("jwt", response.token);
|
localStorage.setItem("jwt", response.token);
|
||||||
callback(response);
|
callback(response);
|
||||||
})
|
})
|
||||||
|
.catch(function(response){
|
||||||
|
console.log(response.data);
|
||||||
|
callback(response.data);
|
||||||
|
})
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.changePassword = function(user, current_password, new_password) {
|
this.changePassword = function(user, current_password, new_password) {
|
||||||
this.getAuthParamsForEmail(email, function(authParams){
|
this.getAuthParamsForEmail(email, function(authParams){
|
||||||
|
if(!authParams) {
|
||||||
|
callback(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: current_password, email: user.email}, authParams), function(currentKeys) {
|
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: current_password, email: user.email}, authParams), function(currentKeys) {
|
||||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: new_password, email: user.email}, authParams), function(newKeys){
|
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: new_password, email: user.email}, authParams), function(newKeys){
|
||||||
var data = {};
|
var data = {};
|
||||||
@@ -122,7 +145,7 @@ angular.module('app.frontend')
|
|||||||
var user = this.user;
|
var user = this.user;
|
||||||
|
|
||||||
this._performPasswordChange(currentKeys, newKeys, function(response){
|
this._performPasswordChange(currentKeys, newKeys, function(response){
|
||||||
if(response && !response.errors) {
|
if(response && !response.error) {
|
||||||
// this.showNewPasswordForm = false;
|
// this.showNewPasswordForm = false;
|
||||||
// reencrypt data with new mk
|
// reencrypt data with new mk
|
||||||
this.reencryptAllItemsAndSave(user, newKeys.mk, currentKeys.mk, function(success){
|
this.reencryptAllItemsAndSave(user, newKeys.mk, currentKeys.mk, function(success){
|
||||||
@@ -149,7 +172,8 @@ angular.module('app.frontend')
|
|||||||
|
|
||||||
this._performPasswordChange = function(email, current_keys, new_keys, callback) {
|
this._performPasswordChange = function(email, current_keys, new_keys, callback) {
|
||||||
var request = Restangular.one("auth");
|
var request = Restangular.one("auth");
|
||||||
request.user = {password: new_keys.pw, password_confirmation: new_keys.pw, current_password: current_keys.pw, email: email};
|
var params = {password: new_keys.pw, password_confirmation: new_keys.pw, current_password: current_keys.pw, email: email};
|
||||||
|
_.merge(request, params);
|
||||||
request.patch().then(function(response){
|
request.patch().then(function(response){
|
||||||
callback(response);
|
callback(response);
|
||||||
})
|
})
|
||||||
@@ -417,10 +441,11 @@ angular.module('app.frontend')
|
|||||||
localStorage.setItem(key, angular.toJson(value));
|
localStorage.setItem(key, angular.toJson(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.localUser = function() {
|
this.loadLocalItemsAndUser = function() {
|
||||||
var user = {};
|
var user = {};
|
||||||
var items = JSON.parse(localStorage.getItem('items'));
|
var items = JSON.parse(localStorage.getItem('items'));
|
||||||
items = this.mapResponseItemsToLocalModels(items);
|
items = this.mapResponseItemsToLocalModels(items);
|
||||||
|
Item.sortItemsByDate(items);
|
||||||
modelManager.items = items;
|
modelManager.items = items;
|
||||||
user.items = items;
|
user.items = items;
|
||||||
user.shouldMerge = true;
|
user.shouldMerge = true;
|
||||||
|
|||||||
11
app/assets/javascripts/app/services/filters/appDate.js
Normal file
11
app/assets/javascripts/app/services/filters/appDate.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
angular.module('app.frontend')
|
||||||
|
.filter('appDate', function ($filter) {
|
||||||
|
return function (input) {
|
||||||
|
return input ? $filter('date')(new Date(input), 'MM/dd/yyyy', 'UTC') : '';
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter('appDateTime', function ($filter) {
|
||||||
|
return function (input) {
|
||||||
|
return input ? $filter('date')(new Date(input), 'MM/dd/yyyy h:mm a') : '';
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -62,9 +62,7 @@ class ModelManager extends ItemManager {
|
|||||||
|
|
||||||
refreshRelationshipsForTag(tag) {
|
refreshRelationshipsForTag(tag) {
|
||||||
tag.notes = tag.referencesMatchingContentType("Note");
|
tag.notes = tag.referencesMatchingContentType("Note");
|
||||||
tag.notes.sort(function(a,b){
|
Item.sortItemsByDate(tag.notes);
|
||||||
return new Date(b.created_at) - new Date(a.created_at);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshRelationshipsForNote(note) {
|
refreshRelationshipsForNote(note) {
|
||||||
|
|||||||
@@ -98,10 +98,20 @@
|
|||||||
|
|
||||||
.item.account {
|
.item.account {
|
||||||
|
|
||||||
|
.email {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
.link-item {
|
.link-item {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
a {
|
a {
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
color: #00228f;
|
color: #00228f;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@@ -141,16 +151,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
> .action-container {
|
> .action-container {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
.status-title {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtext {
|
.status-title {
|
||||||
font-size: 10px;
|
font-weight: bold;
|
||||||
margin-top: 2px;
|
}
|
||||||
}
|
|
||||||
|
.subtext {
|
||||||
|
font-size: 10px;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: -10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.encryption-confirmation {
|
.encryption-confirmation {
|
||||||
@@ -186,7 +202,6 @@
|
|||||||
> .desc {
|
> .desc {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
// line-height: 18px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,6 +213,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.account-form {
|
.account-form {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
@@ -214,8 +233,3 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.account-menu {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
|
|
||||||
> .date {
|
> .date {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
|
|||||||
@@ -50,39 +50,42 @@
|
|||||||
{{ctrl.resetData.response}}
|
{{ctrl.resetData.response}}
|
||||||
|
|
||||||
.account-item{"ng-if" => "ctrl.user.email"}
|
.account-item{"ng-if" => "ctrl.user.email"}
|
||||||
|
.email {{ctrl.user.email}}
|
||||||
|
.links{"ng-if" => "ctrl.user.email"}
|
||||||
|
.link-item
|
||||||
|
%a{"ng-click" => "ctrl.changePasswordPressed()"} Change Password
|
||||||
|
%form.account-form{"ng-if" => "ctrl.showNewPasswordForm", 'ng-submit' => 'ctrl.submitPasswordChange()', 'name' => "passwordChangeForm"}
|
||||||
|
.form-tag.has-feedback
|
||||||
|
%input.form-control.login-input{:autofocus => 'autofocus', :name => 'current', :placeholder => 'Current password', :required => true, :type => 'password', 'ng-model' => 'ctrl.passwordChangeData.current_password'}
|
||||||
|
.form-tag.has-feedback
|
||||||
|
%input.form-control.login-input{:placeholder => 'New password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'ctrl.passwordChangeData.new_password', "autocomplete" => "new-password"}
|
||||||
|
.form-tag.has-feedback
|
||||||
|
%input.form-control.login-input{:placeholder => 'Confirm password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'ctrl.passwordChangeData.new_password_confirmation', "autocomplete" => "new-password"}
|
||||||
|
%button.btn.dark-button.btn-block{:type => 'submit', "data-style" => "expand-right", "data-size" => "s", "state" => "buttonState"}
|
||||||
|
%span.ladda-label Change Password
|
||||||
|
.panel-status-text{"ng-if" => "ctrl.passwordChangeData.status", "style" => "font-size: 14px;"}
|
||||||
|
{{ctrl.passwordChangeData.status}}
|
||||||
|
.link-item
|
||||||
|
%a{"ng-click" => "ctrl.signOutPressed()"} Sign Out
|
||||||
.meta-container
|
.meta-container
|
||||||
.title Local Encryption
|
.title Local Encryption
|
||||||
.desc Encrypt notes locally before sending to server. Neither the server owner nor an intruder can decrypt your locally encrypted notes.
|
.desc Encrypt notes locally before sending to server. Neither the server owner nor an intruder can decrypt your locally encrypted notes.
|
||||||
.action-container
|
.action-container
|
||||||
%span.status-title Status: enabled.
|
%span.status-title Status:
|
||||||
{{ctrl.encryptionStatusForNotes()}} (shared notes not encrypted)
|
{{ctrl.encryptionStatusForNotes()}} (shared notes not encrypted)
|
||||||
.account-item{"ng-if" => "ctrl.user.email"}
|
.account-item{"ng-if" => "ctrl.user.email"}
|
||||||
.meta-container
|
.meta-container
|
||||||
.title Data Archives
|
.title Data Archives
|
||||||
.desc Note: data archives that you download using the link below are decrypted before save. You should take care to store them in a safe location.
|
.desc Note: data archives that you download using the link below are decrypted before save. You should take care to store them in a safe location.
|
||||||
.action-container
|
.action-container
|
||||||
%a#download-archive{"ng-click" => "ctrl.downloadDataArchive()"} Download Latest Data Archive
|
%a{"ng-click" => "ctrl.downloadDataArchive()"} Download Latest Data Archive
|
||||||
|
%br
|
||||||
%label#import-archive
|
%label#import-archive
|
||||||
%input{"type" => "file", "style" => "display: none;", "file-change" => "", "handler" => "ctrl.importFileSelected(files)"}
|
%input{"type" => "file", "style" => "display: none;", "file-change" => "->", "handler" => "ctrl.importFileSelected(files)"}
|
||||||
%span
|
%a.disabled
|
||||||
Import Data from Archive
|
%span
|
||||||
|
Import Data from Archive
|
||||||
|
|
||||||
.links{"ng-if" => "ctrl.user.email"}
|
|
||||||
.link-item
|
|
||||||
%a{"ng-click" => "ctrl.changePasswordPressed()"} Change Password
|
|
||||||
%form.account-form{"ng-if" => "ctrl.showNewPasswordForm", 'ng-submit' => 'ctrl.submitPasswordChange()', 'name' => "passwordChangeForm"}
|
|
||||||
.form-tag.has-feedback
|
|
||||||
%input.form-control.login-input{:autofocus => 'autofocus', :name => 'current', :placeholder => 'Current password', :required => true, :type => 'password', 'ng-model' => 'ctrl.passwordChangeData.current_password'}
|
|
||||||
.form-tag.has-feedback
|
|
||||||
%input.form-control.login-input{:placeholder => 'New password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'ctrl.passwordChangeData.new_password', "autocomplete" => "new-password"}
|
|
||||||
.form-tag.has-feedback
|
|
||||||
%input.form-control.login-input{:placeholder => 'Confirm password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'ctrl.passwordChangeData.new_password_confirmation', "autocomplete" => "new-password"}
|
|
||||||
%button.btn.dark-button.btn-block{:type => 'submit', "data-style" => "expand-right", "data-size" => "s", "state" => "buttonState"}
|
|
||||||
%span.ladda-label Change Password
|
|
||||||
.panel-status-text{"ng-if" => "ctrl.passwordChangeData.status", "style" => "font-size: 14px;"}
|
|
||||||
{{ctrl.passwordChangeData.status}}
|
|
||||||
.link-item
|
|
||||||
%a{"ng-click" => "ctrl.signOutPressed()"} Sign Out
|
|
||||||
|
|
||||||
.item
|
.item
|
||||||
%a{"href" => "https://standardnotes.org", "target" => "_blank"}
|
%a{"href" => "https://standardnotes.org", "target" => "_blank"}
|
||||||
|
|||||||
@@ -35,4 +35,4 @@
|
|||||||
"ng-attr-draggable" => "{{note.dummy ? undefined : 'true'}}", "note" => "note"}
|
"ng-attr-draggable" => "{{note.dummy ? undefined : 'true'}}", "note" => "note"}
|
||||||
.name
|
.name
|
||||||
{{note.content.title}}
|
{{note.content.title}}
|
||||||
.date {{note.created_at || 'Now'}}
|
.date {{(note.created_at | appDateTime) || 'Now'}}
|
||||||
|
|||||||
559
vendor/assets/javascripts/transpiled.js
vendored
559
vendor/assets/javascripts/transpiled.js
vendored
@@ -373,7 +373,7 @@ angular.module('app.frontend', ['ui.router', 'restangular', 'oc.lazyLoad', 'angu
|
|||||||
RestangularProvider.setDefaultHeaders({ "Content-Type": "application/json" });
|
RestangularProvider.setDefaultHeaders({ "Content-Type": "application/json" });
|
||||||
|
|
||||||
var url = apiControllerProvider.defaultServerURL();
|
var url = apiControllerProvider.defaultServerURL();
|
||||||
RestangularProvider.setBaseUrl(url);
|
RestangularProvider.setBaseUrl(url + "/api");
|
||||||
|
|
||||||
RestangularProvider.setFullRequestInterceptor(function (element, operation, route, url, headers, params, httpConfig) {
|
RestangularProvider.setFullRequestInterceptor(function (element, operation, route, url, headers, params, httpConfig) {
|
||||||
var token = localStorage.getItem("jwt");
|
var token = localStorage.getItem("jwt");
|
||||||
@@ -767,9 +767,10 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl);
|
|||||||
this.loginData.status = "Generating Login Keys...";
|
this.loginData.status = "Generating Login Keys...";
|
||||||
$timeout(function () {
|
$timeout(function () {
|
||||||
apiController.login(this.loginData.email, this.loginData.user_password, function (response) {
|
apiController.login(this.loginData.email, this.loginData.user_password, function (response) {
|
||||||
if (response.errors) {
|
if (!response || response.error) {
|
||||||
console.log("login error", response.errors);
|
var error = response ? response.error : { message: "An unknown error occured." };
|
||||||
this.loginData.status = response.errors[0];
|
this.loginData.status = null;
|
||||||
|
alert(error.message);
|
||||||
} else {
|
} else {
|
||||||
this.onAuthSuccess(response.user);
|
this.onAuthSuccess(response.user);
|
||||||
}
|
}
|
||||||
@@ -782,8 +783,10 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl);
|
|||||||
|
|
||||||
$timeout(function () {
|
$timeout(function () {
|
||||||
apiController.register(this.loginData.email, this.loginData.user_password, function (response) {
|
apiController.register(this.loginData.email, this.loginData.user_password, function (response) {
|
||||||
if (response.errors) {
|
if (!response || response.error) {
|
||||||
this.loginData.status = response.errors[0];
|
var error = response ? response.error : { message: "An unknown error occured." };
|
||||||
|
this.loginData.status = null;
|
||||||
|
alert(error.message);
|
||||||
} else {
|
} else {
|
||||||
this.onAuthSuccess(response.user);
|
this.onAuthSuccess(response.user);
|
||||||
}
|
}
|
||||||
@@ -873,7 +876,7 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl);
|
|||||||
$rootScope.title = "Notes — Standard Notes";
|
$rootScope.title = "Notes — Standard Notes";
|
||||||
onUserSet();
|
onUserSet();
|
||||||
} else {
|
} else {
|
||||||
$scope.defaultUser = new User(apiController.localUser());
|
$scope.defaultUser = new User(apiController.loadLocalItemsAndUser());
|
||||||
onUserSet();
|
onUserSet();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -994,7 +997,7 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$scope.headerLogout = function () {
|
$scope.headerLogout = function () {
|
||||||
$scope.defaultUser = apiController.localUser();
|
$scope.defaultUser = apiController.loadLocalItemsAndUser();
|
||||||
$scope.tags = $scope.defaultUser.tags;
|
$scope.tags = $scope.defaultUser.tags;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -1279,6 +1282,14 @@ var Item = function () {
|
|||||||
|
|
||||||
_.merge(this, json_obj);
|
_.merge(this, json_obj);
|
||||||
|
|
||||||
|
if (this.created_at) {
|
||||||
|
this.created_at = new Date(this.created_at);
|
||||||
|
this.updated_at = new Date(this.updated_at);
|
||||||
|
} else {
|
||||||
|
this.created_at = new Date();
|
||||||
|
this.updated_at = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.uuid) {
|
if (!this.uuid) {
|
||||||
this.uuid = Neeto.crypto.generateUUID();
|
this.uuid = Neeto.crypto.generateUUID();
|
||||||
}
|
}
|
||||||
@@ -1352,6 +1363,13 @@ var Item = function () {
|
|||||||
value: function presentationURL() {
|
value: function presentationURL() {
|
||||||
return this.presentation_url;
|
return this.presentation_url;
|
||||||
}
|
}
|
||||||
|
}], [{
|
||||||
|
key: 'sortItemsByDate',
|
||||||
|
value: function sortItemsByDate(items) {
|
||||||
|
items.sort(function (a, b) {
|
||||||
|
return new Date(b.created_at) - new Date(a.created_at);
|
||||||
|
});
|
||||||
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
return Item;
|
return Item;
|
||||||
@@ -1536,6 +1554,9 @@ var User = function User(json_obj) {
|
|||||||
var request = Restangular.one("auth", "params");
|
var request = Restangular.one("auth", "params");
|
||||||
request.get({ email: email }).then(function (response) {
|
request.get({ email: email }).then(function (response) {
|
||||||
callback(response.plain());
|
callback(response.plain());
|
||||||
|
}).catch(function (response) {
|
||||||
|
console.log("Error getting current user", response);
|
||||||
|
callback(response.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1551,21 +1572,30 @@ var User = function User(json_obj) {
|
|||||||
items = this.mapResponseItemsToLocalModels(items);
|
items = this.mapResponseItemsToLocalModels(items);
|
||||||
var user = _.omit(plain, ["items"]);
|
var user = _.omit(plain, ["items"]);
|
||||||
callback(user, items);
|
callback(user, items);
|
||||||
}.bind(this)).catch(function (error) {
|
}.bind(this)).catch(function (response) {
|
||||||
console.log("Error getting current user", error);
|
console.log("Error getting current user", response);
|
||||||
callback(null);
|
callback(response.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.login = function (email, password, callback) {
|
this.login = function (email, password, callback) {
|
||||||
this.getAuthParamsForEmail(email, function (authParams) {
|
this.getAuthParamsForEmail(email, function (authParams) {
|
||||||
|
if (!authParams) {
|
||||||
|
callback(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({ email: email, password: password }, authParams), function (keys) {
|
Neeto.crypto.computeEncryptionKeysForUser(_.merge({ email: email, password: password }, authParams), function (keys) {
|
||||||
this.setMk(keys.mk);
|
this.setMk(keys.mk);
|
||||||
var request = Restangular.one("auth/sign_in");
|
var request = Restangular.one("auth/sign_in");
|
||||||
request.user = { password: keys.pw, email: email };
|
console.log("sending pw", keys.pw);
|
||||||
|
var params = { password: keys.pw, email: email };
|
||||||
|
_.merge(request, params);
|
||||||
request.post().then(function (response) {
|
request.post().then(function (response) {
|
||||||
localStorage.setItem("jwt", response.token);
|
localStorage.setItem("jwt", response.token);
|
||||||
callback(response);
|
callback(response);
|
||||||
|
}).catch(function (response) {
|
||||||
|
console.log(response.data);
|
||||||
|
callback(response.data);
|
||||||
});
|
});
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
@@ -1576,16 +1606,24 @@ var User = function User(json_obj) {
|
|||||||
this.setMk(keys.mk);
|
this.setMk(keys.mk);
|
||||||
keys.mk = null;
|
keys.mk = null;
|
||||||
var request = Restangular.one("auth");
|
var request = Restangular.one("auth");
|
||||||
request.user = _.merge({ password: keys.pw, email: email }, keys);
|
var params = _.merge({ password: keys.pw, email: email }, keys);
|
||||||
|
_.merge(request, params);
|
||||||
request.post().then(function (response) {
|
request.post().then(function (response) {
|
||||||
localStorage.setItem("jwt", response.token);
|
localStorage.setItem("jwt", response.token);
|
||||||
callback(response);
|
callback(response);
|
||||||
|
}).catch(function (response) {
|
||||||
|
console.log(response.data);
|
||||||
|
callback(response.data);
|
||||||
});
|
});
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
this.changePassword = function (user, current_password, new_password) {
|
this.changePassword = function (user, current_password, new_password) {
|
||||||
this.getAuthParamsForEmail(email, function (authParams) {
|
this.getAuthParamsForEmail(email, function (authParams) {
|
||||||
|
if (!authParams) {
|
||||||
|
callback(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({ password: current_password, email: user.email }, authParams), function (currentKeys) {
|
Neeto.crypto.computeEncryptionKeysForUser(_.merge({ password: current_password, email: user.email }, authParams), function (currentKeys) {
|
||||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({ password: new_password, email: user.email }, authParams), function (newKeys) {
|
Neeto.crypto.computeEncryptionKeysForUser(_.merge({ password: new_password, email: user.email }, authParams), function (newKeys) {
|
||||||
var data = {};
|
var data = {};
|
||||||
@@ -1596,7 +1634,7 @@ var User = function User(json_obj) {
|
|||||||
var user = this.user;
|
var user = this.user;
|
||||||
|
|
||||||
this._performPasswordChange(currentKeys, newKeys, function (response) {
|
this._performPasswordChange(currentKeys, newKeys, function (response) {
|
||||||
if (response && !response.errors) {
|
if (response && !response.error) {
|
||||||
// this.showNewPasswordForm = false;
|
// this.showNewPasswordForm = false;
|
||||||
// reencrypt data with new mk
|
// reencrypt data with new mk
|
||||||
this.reencryptAllItemsAndSave(user, newKeys.mk, currentKeys.mk, function (success) {
|
this.reencryptAllItemsAndSave(user, newKeys.mk, currentKeys.mk, function (success) {
|
||||||
@@ -1623,7 +1661,8 @@ var User = function User(json_obj) {
|
|||||||
|
|
||||||
this._performPasswordChange = function (email, current_keys, new_keys, callback) {
|
this._performPasswordChange = function (email, current_keys, new_keys, callback) {
|
||||||
var request = Restangular.one("auth");
|
var request = Restangular.one("auth");
|
||||||
request.user = { password: new_keys.pw, password_confirmation: new_keys.pw, current_password: current_keys.pw, email: email };
|
var params = { password: new_keys.pw, password_confirmation: new_keys.pw, current_password: current_keys.pw, email: email };
|
||||||
|
_.merge(request, params);
|
||||||
request.patch().then(function (response) {
|
request.patch().then(function (response) {
|
||||||
callback(response);
|
callback(response);
|
||||||
});
|
});
|
||||||
@@ -1882,10 +1921,11 @@ var User = function User(json_obj) {
|
|||||||
localStorage.setItem(key, angular.toJson(value));
|
localStorage.setItem(key, angular.toJson(value));
|
||||||
};
|
};
|
||||||
|
|
||||||
this.localUser = function () {
|
this.loadLocalItemsAndUser = function () {
|
||||||
var user = {};
|
var user = {};
|
||||||
var items = JSON.parse(localStorage.getItem('items'));
|
var items = JSON.parse(localStorage.getItem('items'));
|
||||||
items = this.mapResponseItemsToLocalModels(items);
|
items = this.mapResponseItemsToLocalModels(items);
|
||||||
|
Item.sortItemsByDate(items);
|
||||||
modelManager.items = items;
|
modelManager.items = items;
|
||||||
user.items = items;
|
user.items = items;
|
||||||
user.shouldMerge = true;
|
user.shouldMerge = true;
|
||||||
@@ -1999,246 +2039,6 @@ var User = function User(json_obj) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
;
|
|
||||||
var ItemManager = function () {
|
|
||||||
function ItemManager() {
|
|
||||||
_classCallCheck(this, ItemManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
_createClass(ItemManager, [{
|
|
||||||
key: 'referencesForItemId',
|
|
||||||
value: function referencesForItemId(itemId) {
|
|
||||||
return _.find(this.items, { uuid: itemId });
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'resolveReferences',
|
|
||||||
value: function resolveReferences() {
|
|
||||||
this.items.forEach(function (item) {
|
|
||||||
// build out references, safely handle broken references
|
|
||||||
item.content.references = _.reduce(item.content.references, function (accumulator, reference) {
|
|
||||||
var item = this.referencesForItemId(reference.uuid);
|
|
||||||
if (item) {
|
|
||||||
accumulator.push(item);
|
|
||||||
}
|
|
||||||
return accumulator;
|
|
||||||
}.bind(this), []);
|
|
||||||
}.bind(this));
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'itemsForContentType',
|
|
||||||
value: function itemsForContentType(contentType) {
|
|
||||||
return this.items.filter(function (item) {
|
|
||||||
return item.content_type == contentType;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'addItem',
|
|
||||||
value: function addItem(item) {
|
|
||||||
this.items.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns dirty item references that need saving
|
|
||||||
|
|
||||||
}, {
|
|
||||||
key: 'deleteItem',
|
|
||||||
value: function deleteItem(item) {
|
|
||||||
var dirty = [];
|
|
||||||
_.remove(this.items, item);
|
|
||||||
var length = item.content.references.length;
|
|
||||||
// note that references are deleted in this for loop, so you have to be careful how you iterate
|
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
var referencedItem = item.content.references[0];
|
|
||||||
// console.log("removing references between items", referencedItem, item);
|
|
||||||
var _dirty = this.removeReferencesBetweenItems(referencedItem, item);
|
|
||||||
dirty = dirty.concat(_dirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dirty;
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'removeReferencesBetweenItems',
|
|
||||||
value: function removeReferencesBetweenItems(itemOne, itemTwo) {
|
|
||||||
itemOne.removeReference(itemTwo);
|
|
||||||
itemTwo.removeReference(itemOne);
|
|
||||||
return [itemOne, itemTwo];
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'createReferencesBetweenItems',
|
|
||||||
value: function createReferencesBetweenItems(itemOne, itemTwo) {
|
|
||||||
itemOne.addReference(itemTwo);
|
|
||||||
itemTwo.addReference(itemOne);
|
|
||||||
return [itemOne, itemTwo];
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'items',
|
|
||||||
set: function set(items) {
|
|
||||||
this._items = items;
|
|
||||||
this.resolveReferences();
|
|
||||||
},
|
|
||||||
get: function get() {
|
|
||||||
return this._items;
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
|
|
||||||
return ItemManager;
|
|
||||||
}();
|
|
||||||
|
|
||||||
angular.module('app.frontend').service('itemManager', ItemManager);
|
|
||||||
;angular.module('app.frontend').service('markdownRenderer', function ($sce) {
|
|
||||||
|
|
||||||
marked.setOptions({
|
|
||||||
breaks: true,
|
|
||||||
sanitize: true
|
|
||||||
});
|
|
||||||
|
|
||||||
this.renderedContentForText = function (text) {
|
|
||||||
if (!text || text.length == 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return marked(text);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.renderHtml = function (html_code) {
|
|
||||||
return $sce.trustAsHtml(html_code);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
;
|
|
||||||
var ModelManager = function (_ItemManager) {
|
|
||||||
_inherits(ModelManager, _ItemManager);
|
|
||||||
|
|
||||||
function ModelManager() {
|
|
||||||
_classCallCheck(this, ModelManager);
|
|
||||||
|
|
||||||
var _this5 = _possibleConstructorReturn(this, (ModelManager.__proto__ || Object.getPrototypeOf(ModelManager)).call(this));
|
|
||||||
|
|
||||||
_this5.notes = [];
|
|
||||||
_this5.groups = [];
|
|
||||||
_this5.dirtyItems = [];
|
|
||||||
return _this5;
|
|
||||||
}
|
|
||||||
|
|
||||||
_createClass(ModelManager, [{
|
|
||||||
key: 'addDirtyItems',
|
|
||||||
value: function addDirtyItems(items) {
|
|
||||||
if (!(items instanceof Array)) {
|
|
||||||
items = [items];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dirtyItems = this.dirtyItems.concat(items);
|
|
||||||
this.dirtyItems = _.uniq(this.dirtyItems);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'clearDirtyItems',
|
|
||||||
value: function clearDirtyItems() {
|
|
||||||
this.dirtyItems = [];
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'addNote',
|
|
||||||
value: function addNote(note) {
|
|
||||||
if (!_.find(this.notes, { uuid: note.uuid })) {
|
|
||||||
this.notes.unshift(note);
|
|
||||||
this.addItem(note);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'addTag',
|
|
||||||
value: function addTag(tag) {
|
|
||||||
this.tags.unshift(tag);
|
|
||||||
this.addItem(tag);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'addTagToNote',
|
|
||||||
value: function addTagToNote(tag, note) {
|
|
||||||
var dirty = this.createReferencesBetweenItems(tag, note);
|
|
||||||
this.refreshRelationshipsForTag(tag);
|
|
||||||
this.refreshRelationshipsForNote(note);
|
|
||||||
this.addDirtyItems(dirty);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'refreshRelationshipsForTag',
|
|
||||||
value: function refreshRelationshipsForTag(tag) {
|
|
||||||
tag.notes = tag.referencesMatchingContentType("Note");
|
|
||||||
tag.notes.sort(function (a, b) {
|
|
||||||
return new Date(b.created_at) - new Date(a.created_at);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'refreshRelationshipsForNote',
|
|
||||||
value: function refreshRelationshipsForNote(note) {
|
|
||||||
note.tags = note.referencesMatchingContentType("Tag");
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'removeTagFromNote',
|
|
||||||
value: function removeTagFromNote(tag, note) {
|
|
||||||
var dirty = this.removeReferencesBetweenItems(tag, note);
|
|
||||||
this.addDirtyItems(dirty);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'deleteNote',
|
|
||||||
value: function deleteNote(note) {
|
|
||||||
var dirty = this.deleteItem(note);
|
|
||||||
_.remove(this.notes, note);
|
|
||||||
this.addDirtyItems(dirty);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'deleteTag',
|
|
||||||
value: function deleteTag(tag) {
|
|
||||||
var dirty = this.deleteItem(tag);
|
|
||||||
_.remove(this.tags, tag);
|
|
||||||
this.addDirtyItems(dirty);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'filteredNotes',
|
|
||||||
value: function filteredNotes() {
|
|
||||||
return Note.filterDummyNotes(this.notes);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'items',
|
|
||||||
set: function set(items) {
|
|
||||||
_set(ModelManager.prototype.__proto__ || Object.getPrototypeOf(ModelManager.prototype), 'items', items, this);
|
|
||||||
this.notes = this.itemsForContentType("Note");
|
|
||||||
this.notes.forEach(function (note) {
|
|
||||||
note.updateReferencesLocalMapping();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.tags = this.itemsForContentType("Tag");
|
|
||||||
this.tags.forEach(function (tag) {
|
|
||||||
tag.updateReferencesLocalMapping();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
get: function get() {
|
|
||||||
return _get(ModelManager.prototype.__proto__ || Object.getPrototypeOf(ModelManager.prototype), 'items', this);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: 'filteredNotes',
|
|
||||||
get: function get() {
|
|
||||||
return Note.filterDummyNotes(this.notes);
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
|
|
||||||
return ModelManager;
|
|
||||||
}(ItemManager);
|
|
||||||
|
|
||||||
angular.module('app.frontend').service('modelManager', ModelManager);
|
|
||||||
;angular.module('app.frontend').service('serverSideValidation', function ($sce) {
|
|
||||||
// Show validation errors in form.
|
|
||||||
this.showErrors = function (formErrors, form) {
|
|
||||||
angular.forEach(formErrors, function (errors, key) {
|
|
||||||
if (typeof form[key] !== 'undefined') {
|
|
||||||
form[key].$setDirty();
|
|
||||||
form[key].$setValidity('server', false);
|
|
||||||
form[key].$error.server = $sce.trustAsHtml(errors.join(', '));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get validation errors from server response and show them in form.
|
|
||||||
this.parseErrors = function (response, form) {
|
|
||||||
if (response.status === 422) {
|
|
||||||
this.showErrors(response.data, form);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
;angular.module('app.frontend').directive('mbAutofocus', ['$timeout', function ($timeout) {
|
;angular.module('app.frontend').directive('mbAutofocus', ['$timeout', function ($timeout) {
|
||||||
return {
|
return {
|
||||||
restrict: 'A',
|
restrict: 'A',
|
||||||
@@ -2580,6 +2380,253 @@ angular.module('app.frontend').directive('typewrite', ['$timeout', function ($ti
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}]);
|
}]);
|
||||||
|
;angular.module('app.frontend').filter('appDate', function ($filter) {
|
||||||
|
return function (input) {
|
||||||
|
return input ? $filter('date')(new Date(input), 'MM/dd/yyyy', 'UTC') : '';
|
||||||
|
};
|
||||||
|
}).filter('appDateTime', function ($filter) {
|
||||||
|
return function (input) {
|
||||||
|
return input ? $filter('date')(new Date(input), 'MM/dd/yyyy h:mm a') : '';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
;
|
||||||
|
var ItemManager = function () {
|
||||||
|
function ItemManager() {
|
||||||
|
_classCallCheck(this, ItemManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(ItemManager, [{
|
||||||
|
key: 'referencesForItemId',
|
||||||
|
value: function referencesForItemId(itemId) {
|
||||||
|
return _.find(this.items, { uuid: itemId });
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'resolveReferences',
|
||||||
|
value: function resolveReferences() {
|
||||||
|
this.items.forEach(function (item) {
|
||||||
|
// build out references, safely handle broken references
|
||||||
|
item.content.references = _.reduce(item.content.references, function (accumulator, reference) {
|
||||||
|
var item = this.referencesForItemId(reference.uuid);
|
||||||
|
if (item) {
|
||||||
|
accumulator.push(item);
|
||||||
|
}
|
||||||
|
return accumulator;
|
||||||
|
}.bind(this), []);
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'itemsForContentType',
|
||||||
|
value: function itemsForContentType(contentType) {
|
||||||
|
return this.items.filter(function (item) {
|
||||||
|
return item.content_type == contentType;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'addItem',
|
||||||
|
value: function addItem(item) {
|
||||||
|
this.items.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns dirty item references that need saving
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'deleteItem',
|
||||||
|
value: function deleteItem(item) {
|
||||||
|
var dirty = [];
|
||||||
|
_.remove(this.items, item);
|
||||||
|
var length = item.content.references.length;
|
||||||
|
// note that references are deleted in this for loop, so you have to be careful how you iterate
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
var referencedItem = item.content.references[0];
|
||||||
|
// console.log("removing references between items", referencedItem, item);
|
||||||
|
var _dirty = this.removeReferencesBetweenItems(referencedItem, item);
|
||||||
|
dirty = dirty.concat(_dirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dirty;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'removeReferencesBetweenItems',
|
||||||
|
value: function removeReferencesBetweenItems(itemOne, itemTwo) {
|
||||||
|
itemOne.removeReference(itemTwo);
|
||||||
|
itemTwo.removeReference(itemOne);
|
||||||
|
return [itemOne, itemTwo];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'createReferencesBetweenItems',
|
||||||
|
value: function createReferencesBetweenItems(itemOne, itemTwo) {
|
||||||
|
itemOne.addReference(itemTwo);
|
||||||
|
itemTwo.addReference(itemOne);
|
||||||
|
return [itemOne, itemTwo];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'items',
|
||||||
|
set: function set(items) {
|
||||||
|
this._items = items;
|
||||||
|
this.resolveReferences();
|
||||||
|
},
|
||||||
|
get: function get() {
|
||||||
|
return this._items;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ItemManager;
|
||||||
|
}();
|
||||||
|
|
||||||
|
angular.module('app.frontend').service('itemManager', ItemManager);
|
||||||
|
;angular.module('app.frontend').service('markdownRenderer', function ($sce) {
|
||||||
|
|
||||||
|
marked.setOptions({
|
||||||
|
breaks: true,
|
||||||
|
sanitize: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this.renderedContentForText = function (text) {
|
||||||
|
if (!text || text.length == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return marked(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.renderHtml = function (html_code) {
|
||||||
|
return $sce.trustAsHtml(html_code);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
;
|
||||||
|
var ModelManager = function (_ItemManager) {
|
||||||
|
_inherits(ModelManager, _ItemManager);
|
||||||
|
|
||||||
|
function ModelManager() {
|
||||||
|
_classCallCheck(this, ModelManager);
|
||||||
|
|
||||||
|
var _this5 = _possibleConstructorReturn(this, (ModelManager.__proto__ || Object.getPrototypeOf(ModelManager)).call(this));
|
||||||
|
|
||||||
|
_this5.notes = [];
|
||||||
|
_this5.groups = [];
|
||||||
|
_this5.dirtyItems = [];
|
||||||
|
return _this5;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(ModelManager, [{
|
||||||
|
key: 'addDirtyItems',
|
||||||
|
value: function addDirtyItems(items) {
|
||||||
|
if (!(items instanceof Array)) {
|
||||||
|
items = [items];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dirtyItems = this.dirtyItems.concat(items);
|
||||||
|
this.dirtyItems = _.uniq(this.dirtyItems);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'clearDirtyItems',
|
||||||
|
value: function clearDirtyItems() {
|
||||||
|
this.dirtyItems = [];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'addNote',
|
||||||
|
value: function addNote(note) {
|
||||||
|
if (!_.find(this.notes, { uuid: note.uuid })) {
|
||||||
|
this.notes.unshift(note);
|
||||||
|
this.addItem(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'addTag',
|
||||||
|
value: function addTag(tag) {
|
||||||
|
this.tags.unshift(tag);
|
||||||
|
this.addItem(tag);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'addTagToNote',
|
||||||
|
value: function addTagToNote(tag, note) {
|
||||||
|
var dirty = this.createReferencesBetweenItems(tag, note);
|
||||||
|
this.refreshRelationshipsForTag(tag);
|
||||||
|
this.refreshRelationshipsForNote(note);
|
||||||
|
this.addDirtyItems(dirty);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'refreshRelationshipsForTag',
|
||||||
|
value: function refreshRelationshipsForTag(tag) {
|
||||||
|
tag.notes = tag.referencesMatchingContentType("Note");
|
||||||
|
Item.sortItemsByDate(tag.notes);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'refreshRelationshipsForNote',
|
||||||
|
value: function refreshRelationshipsForNote(note) {
|
||||||
|
note.tags = note.referencesMatchingContentType("Tag");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'removeTagFromNote',
|
||||||
|
value: function removeTagFromNote(tag, note) {
|
||||||
|
var dirty = this.removeReferencesBetweenItems(tag, note);
|
||||||
|
this.addDirtyItems(dirty);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'deleteNote',
|
||||||
|
value: function deleteNote(note) {
|
||||||
|
var dirty = this.deleteItem(note);
|
||||||
|
_.remove(this.notes, note);
|
||||||
|
this.addDirtyItems(dirty);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'deleteTag',
|
||||||
|
value: function deleteTag(tag) {
|
||||||
|
var dirty = this.deleteItem(tag);
|
||||||
|
_.remove(this.tags, tag);
|
||||||
|
this.addDirtyItems(dirty);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'filteredNotes',
|
||||||
|
value: function filteredNotes() {
|
||||||
|
return Note.filterDummyNotes(this.notes);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'items',
|
||||||
|
set: function set(items) {
|
||||||
|
_set(ModelManager.prototype.__proto__ || Object.getPrototypeOf(ModelManager.prototype), 'items', items, this);
|
||||||
|
this.notes = this.itemsForContentType("Note");
|
||||||
|
this.notes.forEach(function (note) {
|
||||||
|
note.updateReferencesLocalMapping();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tags = this.itemsForContentType("Tag");
|
||||||
|
this.tags.forEach(function (tag) {
|
||||||
|
tag.updateReferencesLocalMapping();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get: function get() {
|
||||||
|
return _get(ModelManager.prototype.__proto__ || Object.getPrototypeOf(ModelManager.prototype), 'items', this);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'filteredNotes',
|
||||||
|
get: function get() {
|
||||||
|
return Note.filterDummyNotes(this.notes);
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return ModelManager;
|
||||||
|
}(ItemManager);
|
||||||
|
|
||||||
|
angular.module('app.frontend').service('modelManager', ModelManager);
|
||||||
|
;angular.module('app.frontend').service('serverSideValidation', function ($sce) {
|
||||||
|
// Show validation errors in form.
|
||||||
|
this.showErrors = function (formErrors, form) {
|
||||||
|
angular.forEach(formErrors, function (errors, key) {
|
||||||
|
if (typeof form[key] !== 'undefined') {
|
||||||
|
form[key].$setDirty();
|
||||||
|
form[key].$setValidity('server', false);
|
||||||
|
form[key].$error.server = $sce.trustAsHtml(errors.join(', '));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get validation errors from server response and show them in form.
|
||||||
|
this.parseErrors = function (response, form) {
|
||||||
|
if (response.status === 422) {
|
||||||
|
this.showErrors(response.data, form);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
},{}]},{},[1]);
|
},{}]},{},[1]);
|
||||||
|
|||||||
2
vendor/assets/javascripts/transpiled.js.map
vendored
2
vendor/assets/javascripts/transpiled.js.map
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user