es6, itemManager

This commit is contained in:
Mo Bitar
2016-12-15 03:34:39 -06:00
parent 5eadcc2e73
commit 1d4905d17d
9 changed files with 238 additions and 208 deletions

View File

@@ -13,7 +13,7 @@ module.exports = function(grunt) {
js: {
files: ['app/assets/javascripts/**/*.js'],
tasks: ['concat'],
tasks: ['concat', 'babel'],
options: {
spawn: false,
},
@@ -114,6 +114,18 @@ module.exports = function(grunt) {
}
},
babel: {
options: {
sourceMap: true,
presets: ['es2015']
},
dist: {
files: {
'vendor/assets/javascripts/app.js': 'vendor/assets/javascripts/app.js'
}
}
}
ngAnnotate: {
options: {
singleQuotes: true,
@@ -145,5 +157,5 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-ng-annotate');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['haml', 'ngtemplates', 'sass', 'concat', 'ngAnnotate', 'uglify']);
grunt.registerTask('default', ['haml', 'ngtemplates', 'sass', 'concat', 'babel', 'ngAnnotate', 'uglify']);
};

View File

@@ -9,7 +9,7 @@ angular.module('app.frontend')
$scope.allGroup = new Group({name: "All", all: true});
$scope.groups = $scope.defaultUser.groups;
apiController.verifyEncryptionStatusOfAllNotes($scope.defaultUser, function(success){
apiController.verifyEncryptionStatusOfAllItems($scope.defaultUser, function(success){
});
}
@@ -53,7 +53,7 @@ angular.module('app.frontend')
}
$scope.groupsSave = function(group, callback) {
apiController.saveGroup($scope.defaultUser, group, callback);
apiController.saveItem($scope.defaultUser, group, callback);
}
/*
@@ -64,22 +64,15 @@ angular.module('app.frontend')
var originalNote = _.find($scope.defaultUser.notes, {id: noteCopy.id});
if(newGroup.all) {
// going to new group, nil out group_id
originalNote.group_id = null;
} else {
originalNote.group_id = newGroup.id
originalNote.group = newGroup;
$scope.defaultUser.itemManager.removeReferencesBetweenItems(oldGroup, originalNote);
newGroup.notes.unshift(originalNote);
newGroup.notes.sort(function(a,b){
//subtract to get a value that is either negative, positive, or zero.
return new Date(b.created_at) - new Date(a.created_at);
});
if(!newGroup.all) {
$scope.defaultUser.itemManager.createReferencesBetweenItems(newGroup, originalNote);
newGroup.updateReferencesLocalMapping();
}
apiController.saveNote($scope.defaultUser, originalNote, function(note){
_.merge(originalNote, note);
apiController.saveBatchItems($scope.defaultUser, [originalNote, newGroup, oldGroup], function(){
});
}
@@ -91,7 +84,7 @@ angular.module('app.frontend')
var validNotes = Note.filterDummyNotes(group.notes);
if(validNotes == 0) {
// if no more notes, delete group
apiController.deleteGroup($scope.defaultUser, group, function(){
apiController.deleteItem($scope.defaultUser, group, function(){
// force scope groups to update on sub directives
$scope.groups = [];
$timeout(function(){

View File

@@ -1,3 +1,13 @@
var Group = function (json_obj) {
_.merge(this, json_obj);
};
class Group extends Item {
constructor(json_obj) {
_.merge(this, json_obj);
}
updateReferencesLocalMapping() {
super.updateReferencesLocalMapping();
this.notes = this.referencesMatchingContentType("Note");
this.notes.sort(function(a,b){
return new Date(b.created_at) - new Date(a.created_at);
});
}
}

View File

@@ -0,0 +1,29 @@
class Item {
referencesMatchingContentType(contentType) {
return this.references.filter(function(reference){
return reference.content_type == content_type;
});
}
updateReferencesLocalMapping() {
// should be overriden to manage local properties
}
/* Returns true if note is shared individually or via group */
isPublic() {
return this.presentation;
}
isEncrypted() {
return this.encryptionEnabled() && typeof this.content === 'string' ? true : false;
}
encryptionEnabled() {
return this.loc_eek;
}
presentationURL() {
return this.presentation.url;
}
}

View File

@@ -0,0 +1,55 @@
class ItemManager() {
set items(items) {
this.items = items;
resolveReferences();
}
referencesForItemId(itemId) {
return _.find(this.items, {uuid: itemId});
}
resolveReferences() {
this.items.forEach(function(item){
// build out references
_.map(item.references, function(reference){
return referencesForItemId(reference.uuid);
})
});
}
itemsForContentType(contentType) {
this.items.filter(function(item){
return item.content_type == contentType;
});
}
// returns dirty item references that need saving
deleteItem(item) {
_.remove(this.items, item);
item.references.forEach(function(reference){
removeReferencesFromItem(reference, item);
})
return item.references;
}
removeReferencesBetweenItems(itemOne, itemTwo) {
_.remove(itemOne.references, _.find(itemOne.references, {uuid: itemTwo.uuid}));
_.remove(itemTwo.references, _.find(itemTwo.references, {uuid: itemOne.uuid}));
return [itemOne, itemTwo];
}
removeReferencesBetweenItems(itemOne, itemTwo) {
itemOne.references.push(itemTwo);
itemTwo.references.push(itemOne);
return [itemOne, itemTwo];
}
createReferencesBetweenItems(itemOne, itemTwo) {
itemOne.references.push(itemTwo);
itemTwo.references.push(itemOne);
return [itemOne, itemTwo];
}
}

View File

@@ -1,57 +1,63 @@
var Note = function (json_obj) {
var content;
class Note extends Item {
constructor(json_obj) {
var content;
Object.defineProperty(this, "content", {
get: function() {
return content;
},
set: function(value) {
var finalValue = value;
Object.defineProperty(this, "content", {
get: function() {
return content;
},
set: function(value) {
var finalValue = value;
if(typeof value === 'string') {
try {
decodedValue = JSON.parse(value);
finalValue = decodedValue;
}
catch(e) {
finalValue = value;
if(typeof value === 'string') {
try {
decodedValue = JSON.parse(value);
finalValue = decodedValue;
}
catch(e) {
finalValue = value;
}
}
content = finalValue;
},
enumerable: true,
});
this.setContentRaw = function(rawContent) {
content = rawContent;
}
_.merge(this, json_obj);
if(!this.content) {
this.content = {title: "", text: ""};
}
}
filterDummyNotes(notes) {
var filtered = notes.filter(function(note){return note.dummy == false || note.dummy == null});
return filtered;
}
updateReferencesLocalMapping() {
super.updateReferencesLocalMapping();
this.groups = this.referencesMatchingContentType("Group");
}
get hasOnePublicGroup() {
var hasPublicGroup = false;
this.groups.forEach(function(group){
if(group.isPublic()) {
hasPublicGroup = true;
return;
}
})
content = finalValue;
},
enumerable: true,
});
this.setContentRaw = function(rawContent) {
content = rawContent;
return hasPublicGroup;
}
_.merge(this, json_obj);
if(!this.content) {
this.content = {title: "", text: ""};
function isPublic() {
return super.isPublic() || this.hasOnePublicGroup;
}
};
Note.filterDummyNotes = function(notes) {
var filtered = notes.filter(function(note){return note.dummy == false || note.dummy == null});
return filtered;
}
/* Returns true if note is shared individually or via group */
Note.prototype.isPublic = function() {
return this.presentation || (this.group && this.group.presentation);
};
Note.prototype.isEncrypted = function() {
return this.encryptionEnabled() && typeof this.content === 'string' ? true : false;
}
Note.prototype.encryptionEnabled = function() {
return this.loc_eek;
}
Note.prototype.presentationURL = function() {
return this.presentation.url;
}

View File

@@ -1,23 +1,23 @@
var User = function (json_obj) {
_.merge(this, json_obj);
class User {
constructor(json_obj) {
_.merge(this, json_obj);
this.notes = _.map(this.notes, function(json_obj) {
return new Note(json_obj);
});
this.itemManager = new ItemManager();
this.itemManager.items = this.items;
this.items = null;
this.groups = _.map(this.groups, function(json_obj) {
return new Group(json_obj);
});
this.groups.forEach(function(group){
var notes = this.notes.filter(function(note){return note.group_id && note.group_id == group.id});
notes.forEach(function(note){
note.group = group;
this.notes = _.map(this.itemManager.itemsForContentType("Note"), function(json_obj) {
return new Note(json_obj);
})
group.notes = notes;
}.bind(this))
};
User.prototype.filteredNotes = function() {
return Note.filterDummyNotes(this.notes);
this.groups = _.map(this.itemManager.itemsForContentType("Group"), function(json_obj) {
var group = Group(json_obj);
group.updateReferencesLocalMapping();
return group;
})
}
filteredNotes() {
return Note.filterDummyNotes(this.notes);
}
}

View File

@@ -144,7 +144,7 @@ angular.module('app.services')
Ensures that if encryption is disabled, all local notes are uncrypted,
and that if it's enabled, that all local notes are encrypted
*/
this.verifyEncryptionStatusOfAllNotes = function(user, callback) {
this.verifyEncryptionStatusOfAllItems = function(user, callback) {
var allNotes = user.filteredNotes();
var notesNeedingUpdate = [];
allNotes.forEach(function(note){
@@ -168,83 +168,13 @@ angular.module('app.services')
/*
Groups
Items
*/
this.restangularizeGroup = function(group, user) {
var request = Restangular.one("users", user.id).one("groups", group.id);
_.merge(request, group);
return request;
}
this.saveGroup = function(user, group, callback) {
if(user.id) {
if(!group.route) {
group = this.restangularizeGroup(group, user);
}
group.customOperation(group.id ? "put" : "post").then(function(response) {
callback(response.plain());
})
} else {
this.writeUserToLocalStorage(user);
callback(group);
}
}
this.deleteGroup = function(user, group, callback) {
if(!user.id) {
_.remove(user.groups, group);
this.writeUserToLocalStorage(user);
callback(true);
} else {
Restangular.one("users", user.id).one("groups", group.id).remove()
.then(function(response) {
_.remove(user.groups, group);
callback(true);
})
}
}
this.shareGroup = function(user, group, callback) {
Restangular.one("users", user.id).one("groups", group.id).one("presentations").post()
.then(function(response){
var presentation = response.plain();
_.merge(group, {presentation: presentation});
callback(presentation);
if(group.notes.length > 0) {
// decrypt notes
this.saveBatchNotes(user, group.notes, function(success){})
}
}.bind(this))
}
this.unshareGroup = function(user, group, callback) {
var request = Restangular.one("users", user.id).one("groups", group.id).one("presentations", group.presentation.id);
request.remove().then(function(response){
group.presentation = null;
callback(null);
if(group.notes.length > 0) {
// encrypt notes
var notes = group.notes;
this.saveBatchNotes(user, notes, function(success){})
}
}.bind(this))
}
/*
Notes
*/
this.saveBatchNotes = function(user, notes, callback) {
var request = Restangular.one("users", user.id).one("notes/batch_update");
request.notes = _.map(notes, function(note){
return this.createRequestParamsFromNote(note, user);
this.saveBatchItems = function(user, items, callback) {
var request = Restangular.one("users", user.uuid).one("items/batch_update");
request.items = _.map(items, function(item){
return this.createRequestParamsFromItem(item, user);
}.bind(this));
request.put().then(function(response){
var success = response.plain().success;
@@ -252,95 +182,88 @@ angular.module('app.services')
})
}
this.saveNote = function(user, note, callback) {
this.saveItem = function(user, item, callback) {
if(!user.id) {
this.writeUserToLocalStorage(user);
callback(note);
callback(item);
return;
}
var params = this.createRequestParamsFromNote(note, user);
var params = this.createRequestParamsForItem(item, user);
var request = Restangular.one("users", user.id).one("notes", note.id);
var request = Restangular.one("users", user.uuid).one("item", item.uuid);
_.merge(request, params);
request.customOperation(request.id ? "put" : "post")
request.customOperation(request.uuid ? "put" : "post")
.then(function(response) {
var responseObject = response.plain();
responseObject.content = note.content;
_.merge(note, responseObject);
callback(note);
responseObject.content = item.content;
_.merge(item, responseObject);
callback(item);
})
.catch(function(response){
callback(null);
})
}
this.createRequestParamsFromNote = function(note, user) {
var params = {id: note.id};
this.createRequestParamsForItem = function(item, user) {
var params = {uuid: item.uuid};
if(!note.pending_share && !note.isPublic()) {
if(!item.isPublic()) {
// encrypted
var noteCopy = _.cloneDeep(note);
this.encryptSingleNote(noteCopy, this.retrieveGk());
params.content = noteCopy.content;
params.loc_eek = noteCopy.loc_eek;
var itemCopy = _.cloneDeep(item);
this.encryptSingleNote(itemCopy, this.retrieveGk());
params.content = itemCopy.content;
params.loc_eek = itemCopy.loc_eek;
}
else {
// decrypted
params.content = JSON.stringify(note.content);
params.content = JSON.stringify(item.content);
params.loc_eek = null;
}
return params;
}
this.deleteNote = function(user, note, callback) {
this.deleteItem = function(user, item, callback) {
if(!user.id) {
this.writeUserToLocalStorage(user);
callback(true);
} else {
Restangular.one("users", user.id).one("notes", note.id).remove()
Restangular.one("users", user.uuid).one("items", item.uuid).remove()
.then(function(response) {
callback(true);
})
}
}
this.shareNote = function(user, note, callback) {
this.shareItem = function(user, item, callback) {
if(!user.id) {
if(confirm("Note: You are not signed in. Any note you share cannot be edited or unshared.")) {
var request = Restangular.one("notes").one("share");
_.merge(request, {name: note.content.title, content: note.content});
request.post().then(function(response){
var presentation = response.plain();
_.merge(note, {presentation: presentation});
note.locked = true;
this.writeUserToLocalStorage(user);
callback(note);
}.bind(this))
}
alert("You must be signed in to share.");
} else {
var shareFn = function(note, callback) {
Restangular.one("users", user.id).one("notes", note.id).one("presentations").post()
.then(function(response){
var presentation = response.plain();
_.merge(note, {presentation: presentation});
callback(note);
})
}
Restangular.one("users", user.uuid).one("items", item.uuid).one("presentations").post()
.then(function(response){
var presentation = response.plain();
_.merge(item, {presentation: presentation});
callback(item);
note.pending_share = true;
this.saveNote(user, note, function(saved_note){
shareFn(saved_note, callback);
// decrypt references
if(item.references.length > 0) {
this.saveBatchItems(user, item.references, function(success){})
}
})
}
}
this.unshareNote = function(user, note, callback) {
var request = Restangular.one("users", user.id).one("notes", note.id).one("presentations", note.presentation.id);
this.unshareItem = function(user, item, callback) {
var request = Restangular.one("users", user.uuid).one("notes", item.uuid).one("presentations", item.presentation.uuid);
request.remove().then(function(response){
note.presentation = null;
item.presentation = null;
callback(null);
// encrypt references
if(item.references.length > 0) {
this.saveBatchItems(user, item.references, function(success){})
}
})
}
@@ -351,7 +274,7 @@ angular.module('app.services')
this.updatePresentation = function(resource, presentation, callback) {
var request = Restangular.one("users", user.id)
.one(resource.constructor.name.toLowerCase() + "s", resource.id)
.one("items", resource.id)
.one("presentations", resource.presentation.id);
_.merge(request, presentation);
request.patch().then(function(response){

View File

@@ -2,8 +2,10 @@
"name": "neeto",
"version": "1.0.0",
"devDependencies": {
"babel-preset-es2015": "^6.18.0",
"grunt": "^1.0.1",
"grunt-angular-templates": "^1.1.0",
"grunt-babel": "^6.0.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-cssmin": "^1.0.2",
"grunt-contrib-jshint": "~0.10.0",