From 1722eb299c4862d46036ed0ae6411a3be0d17c22 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Thu, 15 Dec 2016 17:37:26 -0600 Subject: [PATCH] working functionality --- app/assets/javascripts/app/app.frontend.js | 4 +- .../app/frontend/controllers/editor.js | 6 +- .../app/frontend/controllers/groups.js | 104 --- .../app/frontend/controllers/header.js | 8 +- .../app/frontend/controllers/home.js | 86 +- .../app/frontend/controllers/notes.js | 49 +- .../app/frontend/controllers/tags.js | 114 +++ .../app/frontend/models/api/item.js | 33 +- .../app/frontend/models/app/note.js | 26 +- .../app/frontend/models/app/tag.js | 14 + app/assets/javascripts/app/frontend/routes.js | 2 +- .../javascripts/app/services/apiController.js | 246 +++--- .../app/services/directives/draggable.js | 4 +- .../app/services/helpers/crypto.js | 13 + .../javascripts/app/services/itemManager.js | 34 +- .../javascripts/app/services/modelManager.js | 39 +- app/assets/stylesheets/app/_mostrap.scss | 2 +- app/assets/stylesheets/app/_notes.scss | 2 +- .../app/{_groups.scss => _tags.scss} | 8 +- app/assets/stylesheets/frontend.css.scss | 2 +- .../templates/frontend/auth/forgot.html.haml | 2 +- .../templates/frontend/auth/login.html.haml | 4 +- .../templates/frontend/auth/reset.html.haml | 4 +- .../templates/frontend/groups.html.haml | 16 - .../templates/frontend/header.html.haml | 14 +- app/assets/templates/frontend/home.html.haml | 8 +- .../frontend/modals/username.html.haml | 2 +- app/assets/templates/frontend/notes.html.haml | 22 +- app/assets/templates/frontend/tags.html.haml | 18 + vendor/assets/javascripts/transpiled.js | 816 ++++++++++-------- vendor/assets/javascripts/transpiled.js.map | 2 +- 31 files changed, 944 insertions(+), 760 deletions(-) delete mode 100644 app/assets/javascripts/app/frontend/controllers/groups.js create mode 100644 app/assets/javascripts/app/frontend/controllers/tags.js rename app/assets/stylesheets/app/{_groups.scss => _tags.scss} (92%) delete mode 100644 app/assets/templates/frontend/groups.html.haml create mode 100644 app/assets/templates/frontend/tags.html.haml diff --git a/app/assets/javascripts/app/app.frontend.js b/app/assets/javascripts/app/app.frontend.js index 2021921d1..6275f1194 100644 --- a/app/assets/javascripts/app/app.frontend.js +++ b/app/assets/javascripts/app/app.frontend.js @@ -14,9 +14,10 @@ angular ]) // Configure path to API .config(function (RestangularProvider, apiControllerProvider) { + RestangularProvider.setDefaultHeaders({"Content-Type": "application/json"}); + var url = apiControllerProvider.defaultServerURL(); RestangularProvider.setBaseUrl(url); - console.log(url); RestangularProvider.setFullRequestInterceptor(function(element, operation, route, url, headers, params, httpConfig) { var token = localStorage.getItem("jwt"); @@ -32,4 +33,3 @@ angular }; }); }) -} diff --git a/app/assets/javascripts/app/frontend/controllers/editor.js b/app/assets/javascripts/app/frontend/controllers/editor.js index 78ca6c2b6..c21ee5599 100644 --- a/app/assets/javascripts/app/frontend/controllers/editor.js +++ b/app/assets/javascripts/app/frontend/controllers/editor.js @@ -63,7 +63,7 @@ angular.module('app.frontend') } } }) - .controller('EditorCtrl', function ($sce, $timeout, apiController, markdownRenderer, $rootScope) { + .controller('EditorCtrl', function ($sce, $timeout, apiController, modelManager, markdownRenderer, $rootScope) { this.demoNotes = [ {title: "Live print a file with tail", content: "tail -f log/production.log"}, @@ -74,14 +74,14 @@ angular.module('app.frontend') {title: "NPM install without sudo", content: "sudo chown -R $(whoami) ~/.npm"}, {title: "Email validation regex", content: "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"}, {title: "Ruby generate 256 bit key", content: "Digest::SHA256.hexdigest(SecureRandom.random_bytes(32))"}, - {title: "Mac add user to user group", content: "sudo dseditgroup -o edit -a USERNAME -t user GROUPNAME"}, + {title: "Mac add user to user tag", content: "sudo dsedittag -o edit -a USERNAME -t user GROUPNAME"}, {title: "Kill Mac OS System Apache", content: "sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist"}, {title: "Docker run with mount binding and port", content: "docker run -v /home/vagrant/www/app:/var/www/app -p 8080:80 -d kpi/s3"}, {title: "MySQL grant privileges", content: "GRANT [type of permission] ON [database name].[table name] TO ‘[username]’@'%’;"}, {title: "MySQL list users", content: "SELECT User FROM mysql.user;"}, ]; - this.showSampler = !this.user.id && this.user.filteredNotes().length == 0; + this.showSampler = !this.user.id && modelManager.filteredNotes.length == 0; this.demoNoteNames = _.map(this.demoNotes, function(note){ return note.title; diff --git a/app/assets/javascripts/app/frontend/controllers/groups.js b/app/assets/javascripts/app/frontend/controllers/groups.js deleted file mode 100644 index 567718738..000000000 --- a/app/assets/javascripts/app/frontend/controllers/groups.js +++ /dev/null @@ -1,104 +0,0 @@ -angular.module('app.frontend') - .directive("groupsSection", function(){ - return { - restrict: 'E', - scope: { - addNew: "&", - selectionMade: "&", - willSelect: "&", - save: "&", - groups: "=", - allGroup: "=", - user: "=", - updateNoteGroup: "&" - }, - templateUrl: 'frontend/groups.html', - replace: true, - controller: 'GroupsCtrl', - controllerAs: 'ctrl', - bindToController: true, - - link:function(scope, elem, attrs, ctrl) { - scope.$watch('ctrl.groups', function(newGroups){ - if(newGroups) { - ctrl.setGroups(newGroups); - } - }); - } - } - }) - .controller('GroupsCtrl', function () { - - var initialLoad = true; - - this.setGroups = function(groups) { - if(initialLoad) { - initialLoad = false; - this.selectGroup(this.allGroup); - } else { - if(groups && groups.length > 0) { - this.selectGroup(groups[0]); - } - } - } - - this.selectGroup = function(group) { - this.willSelect()(group); - this.selectedGroup = group; - this.selectionMade()(group); - } - - this.clickedAddNewGroup = function() { - if(this.editingGroup) { - return; - } - - this.newGroup = new Group({notes : []}); - if(!this.user.uuid) { - this.newGroup.uuid = Neeto.crypto.generateRandomKey() - } - this.selectedGroup = this.newGroup; - this.editingGroup = this.newGroup; - this.addNew()(this.newGroup); - } - - var originalGroupName = ""; - this.onGroupTitleFocus = function(group) { - originalGroupName = group.name; - } - - this.groupTitleDidChange = function(group) { - this.editingGroup = group; - } - - this.saveGroup = function($event, group) { - this.editingGroup = null; - if(group.name.length == 0) { - group.name = originalGroupName; - originalGroupName = ""; - return; - } - - $event.target.blur(); - if(!group.name || group.name.length == 0) { - return; - } - - this.save()(group, function(savedGroup){ - _.merge(group, savedGroup); - this.selectGroup(group); - this.newGroup = null; - }.bind(this)); - } - - this.noteCount = function(group) { - var validNotes = Note.filterDummyNotes(group.notes); - return validNotes.length; - } - - this.handleDrop = function(e, newGroup, note) { - this.updateNoteGroup()(note, newGroup, this.selectedGroup); - }.bind(this) - - - }); diff --git a/app/assets/javascripts/app/frontend/controllers/header.js b/app/assets/javascripts/app/frontend/controllers/header.js index 88bd95f1e..677274614 100644 --- a/app/assets/javascripts/app/frontend/controllers/header.js +++ b/app/assets/javascripts/app/frontend/controllers/header.js @@ -17,7 +17,7 @@ angular.module('app.frontend') } } }) - .controller('HeaderCtrl', function ($auth, $state, apiController, serverSideValidation, $timeout) { + .controller('HeaderCtrl', function ($auth, $state, apiController, modelManager, serverSideValidation, $timeout) { this.changePasswordPressed = function() { this.showNewPasswordForm = !this.showNewPasswordForm; @@ -58,12 +58,12 @@ angular.module('app.frontend') } this.hasLocalData = function() { - return this.user.filteredNotes().length > 0; + return modelManager.filteredNotes.length > 0; } this.mergeLocalChanged = function() { if(!this.user.shouldMerge) { - if(!confirm("Unchecking this option means any locally stored groups and notes you have now will be deleted. Are you sure you want to continue?")) { + if(!confirm("Unchecking this option means any locally stored tags and notes you have now will be deleted. Are you sure you want to continue?")) { this.user.shouldMerge = true; } } @@ -109,7 +109,7 @@ angular.module('app.frontend') } this.encryptionStatusForNotes = function() { - var allNotes = this.user.filteredNotes(); + var allNotes = modelManager.filteredNotes; var countEncrypted = 0; allNotes.forEach(function(note){ if(note.encryptionEnabled()) { diff --git a/app/assets/javascripts/app/frontend/controllers/home.js b/app/assets/javascripts/app/frontend/controllers/home.js index b0fab42e8..8db64341f 100644 --- a/app/assets/javascripts/app/frontend/controllers/home.js +++ b/app/assets/javascripts/app/frontend/controllers/home.js @@ -5,19 +5,19 @@ angular.module('app.frontend') $rootScope.description = "A secure code box for developers to store common commands and useful notes."; var onUserSet = function() { + apiController.setUser($scope.defaultUser); + $scope.allTag = new Tag({all: true}); + $scope.allTag.content.name = "All"; + $scope.tags = modelManager.tags; - $scope.allGroup = new Group({name: "All", all: true}); - $scope.groups = modelManager.groups; - - apiController.verifyEncryptionStatusOfAllItems($scope.defaultUser, function(success){ - - }); + // apiController.verifyEncryptionStatusOfAllItems($scope.defaultUser, function(success){}); } apiController.getCurrentUser(function(response){ if(response && !response.errors) { + console.log("Get user response", response); $scope.defaultUser = new User(response); - modelManager.items = response.items; + modelManager.items = _.map(response.items, function(json_obj){return new Item(json_obj)}); $rootScope.title = "Notes — Neeto"; onUserSet(); } else { @@ -27,44 +27,44 @@ angular.module('app.frontend') }); /* - Groups Ctrl Callbacks + Tags Ctrl Callbacks */ - $scope.updateAllGroup = function() { - $scope.allGroup.notes = modelManager.filteredNotes; + $scope.updateAllTag = function() { + $scope.allTag.notes = modelManager.filteredNotes; } - $scope.groupsWillMakeSelection = function(group) { - if(group.all) { - $scope.updateAllGroup(); + $scope.tagsWillMakeSelection = function(tag) { + if(tag.all) { + $scope.updateAllTag(); } } - $scope.groupsSelectionMade = function(group) { - if(!group.notes) { - group.notes = []; + $scope.tagsSelectionMade = function(tag) { + if(!tag.notes) { + tag.notes = []; } - $scope.selectedGroup = group; + $scope.selectedTag = tag; } - $scope.groupsAddNew = function(group) { - modelManager.addTag(group); + $scope.tagsAddNew = function(tag) { + modelManager.addTag(tag); } - $scope.groupsSave = function(group, callback) { - apiController.saveItems([group], callback); + $scope.tagsSave = function(tag, callback) { + apiController.saveItems([tag], callback); } /* - Called to update the group of a note after drag and drop change + Called to update the tag of a note after drag and drop change The note object is a copy of the original */ - $scope.groupsUpdateNoteGroup = function(noteCopy, newGroup, oldGroup) { + $scope.tagsUpdateNoteTag = function(noteCopy, newTag, oldTag) { var originalNote = _.find($scope.defaultUser.notes, {uuid: noteCopy.uuid}); - modelManager.removeTagFromNote(oldGroup, originalNote); - if(!newGroup.all) { - modelManager.addTagToNote(newGroup, originalNote); + modelManager.removeTagFromNote(oldTag, originalNote); + if(!newTag.all) { + modelManager.addTagToNote(newTag, originalNote); } apiController.saveDirtyItems(function(){}); @@ -74,19 +74,19 @@ angular.module('app.frontend') Notes Ctrl Callbacks */ - $scope.notesRemoveGroup = function(group) { - var validNotes = Note.filterDummyNotes(group.notes); + $scope.notesRemoveTag = function(tag) { + var validNotes = Note.filterDummyNotes(tag.notes); if(validNotes == 0) { - // if no more notes, delete group - apiController.deleteItem($scope.defaultUser, group, function(){ - // force scope groups to update on sub directives - $scope.groups = []; + // if no more notes, delete tag + apiController.deleteItem($scope.defaultUser, tag, function(){ + // force scope tags to update on sub directives + $scope.tags = []; $timeout(function(){ - $scope.groups = modelManager.groups; + $scope.tags = modelManager.tags; }) }); } else { - alert("To delete this group, remove all its notes first."); + alert("To delete this tag, remove all its notes first."); } } @@ -95,15 +95,13 @@ angular.module('app.frontend') } $scope.notesAddNew = function(note) { - if(!$scope.defaultUser.id) { - // generate local id for note - note.id = Neeto.crypto.generateRandomKey(); - } - modelManager.addNote(note); - if(!$scope.selectedGroup.all) { - modelManager.addTagToNote($scope.selectedGroup, note); + if(!$scope.selectedTag.all) { + console.log("add tag"); + modelManager.addTagToNote($scope.selectedTag, note); + } else { + $scope.selectedTag.notes.unshift(note); } } @@ -112,7 +110,9 @@ angular.module('app.frontend') */ $scope.saveNote = function(note, callback) { - apiController.saveItems([note], function(){ + modelManager.addDirtyItems(note); + + apiController.saveDirtyItems(function(){ modelManager.addNote(note); note.hasChanges = false; @@ -144,7 +144,7 @@ angular.module('app.frontend') $scope.headerLogout = function() { $scope.defaultUser = apiController.localUser(); - $scope.groups = $scope.defaultUser.groups; + $scope.tags = $scope.defaultUser.tags; } diff --git a/app/assets/javascripts/app/frontend/controllers/notes.js b/app/assets/javascripts/app/frontend/controllers/notes.js index da0eaff50..d1fc40a38 100644 --- a/app/assets/javascripts/app/frontend/controllers/notes.js +++ b/app/assets/javascripts/app/frontend/controllers/notes.js @@ -5,10 +5,11 @@ angular.module('app.frontend') addNew: "&", selectionMade: "&", remove: "&", - group: "=", + tag: "=", user: "=", - removeGroup: "&" + removeTag: "&" }, + templateUrl: 'frontend/notes.html', replace: true, controller: 'NotesCtrl', @@ -16,15 +17,15 @@ angular.module('app.frontend') bindToController: true, link:function(scope, elem, attrs, ctrl) { - scope.$watch('ctrl.group', function(group, oldGroup){ - if(group) { - ctrl.groupDidChange(group, oldGroup); + scope.$watch('ctrl.tag', function(tag, oldTag){ + if(tag) { + ctrl.tagDidChange(tag, oldTag); } }); } } }) - .controller('NotesCtrl', function (apiController, $timeout, ngDialog, $rootScope) { + .controller('NotesCtrl', function (apiController, modelManager, $timeout, ngDialog, $rootScope) { $rootScope.$on("editorFocused", function(){ this.showMenu = false; @@ -32,15 +33,15 @@ angular.module('app.frontend') var isFirstLoad = true; - this.groupDidChange = function(group, oldGroup) { + this.tagDidChange = function(tag, oldTag) { this.showMenu = false; if(this.selectedNote && this.selectedNote.dummy) { - _.remove(oldGroup.notes, this.selectedNote); + _.remove(oldTag.notes, this.selectedNote); } this.noteFilter.text = ""; - this.setNotes(group.notes, false); + this.setNotes(tag.notes, false); if(isFirstLoad) { $timeout(function(){ @@ -53,31 +54,31 @@ angular.module('app.frontend') isFirstLoad = false; } }.bind(this)) - } else if(group.notes.length == 0) { + } else if(tag.notes.length == 0) { this.createNewNote(); } } - this.selectedGroupDelete = function() { + this.selectedTagDelete = function() { this.showMenu = false; - this.removeGroup()(this.group); + this.removeTag()(this.tag); } - this.selectedGroupShare = function() { + this.selectedTagShare = function() { this.showMenu = false; if(!this.user.id) { - alert("You must be signed in to share a group."); + alert("You must be signed in to share a tag."); return; } - if(this.group.all) { - alert("You cannot share the 'All' group."); + if(this.tag.all) { + alert("You cannot share the 'All' tag."); return; } var callback = function(username) { - apiController.shareItem(this.user, this.group, function(response){ + apiController.shareItem(this.user, this.tag, function(response){ }) }.bind(this); @@ -97,23 +98,23 @@ angular.module('app.frontend') } } - this.selectedGroupUnshare = function() { + this.selectedTagUnshare = function() { this.showMenu = false; - apiController.unshareItem(this.user, this.group, function(response){ + apiController.unshareItem(this.user, this.tag, function(response){ }) } - this.publicUrlForGroup = function() { - return this.group.presentation.url; + this.publicUrlForTag = function() { + return this.tag.presentation.url; } this.setNotes = function(notes, createNew) { this.notes = notes; + console.log("set notes", notes); notes.forEach(function(note){ note.visible = true; }) - apiController.decryptNotesWithLocalKey(notes); this.selectFirstNote(createNew); } @@ -138,7 +139,9 @@ angular.module('app.frontend') var title = "New Note" + (this.notes ? (" " + (this.notes.length + 1)) : ""); this.newNote = new Note({dummy: true}); this.newNote.content.title = title; - modelManager.addTagToNote(this.group, this.newNote); + if(this.tag && !this.tag.all) { + modelManager.addTagToNote(this.tag, this.newNote); + } this.selectNote(this.newNote); this.addNew()(this.newNote); } diff --git a/app/assets/javascripts/app/frontend/controllers/tags.js b/app/assets/javascripts/app/frontend/controllers/tags.js new file mode 100644 index 000000000..6c2064fa5 --- /dev/null +++ b/app/assets/javascripts/app/frontend/controllers/tags.js @@ -0,0 +1,114 @@ +angular.module('app.frontend') + .directive("tagsSection", function(){ + return { + restrict: 'E', + scope: { + addNew: "&", + selectionMade: "&", + willSelect: "&", + save: "&", + tags: "=", + allTag: "=", + user: "=", + updateNoteTag: "&" + }, + templateUrl: 'frontend/tags.html', + replace: true, + controller: 'TagsCtrl', + controllerAs: 'ctrl', + bindToController: true, + + link:function(scope, elem, attrs, ctrl) { + scope.$watch('ctrl.tags', function(newTags){ + if(newTags) { + ctrl.setTags(newTags); + } + }); + + scope.$watch('ctrl.allTag', function(allTag){ + if(allTag) { + ctrl.setAllTag(allTag); + } + }); + } + } + }) + .controller('TagsCtrl', function () { + + var initialLoad = true; + + this.setAllTag = function(allTag) { + this.selectTag(this.allTag); + } + + this.setTags = function(tags) { + if(initialLoad) { + initialLoad = false; + this.selectTag(this.allTag); + } else { + if(tags && tags.length > 0) { + this.selectTag(tags[0]); + } + } + } + + this.selectTag = function(tag) { + this.willSelect()(tag); + this.selectedTag = tag; + this.selectionMade()(tag); + } + + this.clickedAddNewTag = function() { + if(this.editingTag) { + return; + } + + this.newTag = new Tag({notes : []}); + if(!this.user.uuid) { + this.newTag.uuid = Neeto.crypto.generateRandomKey() + } + this.selectedTag = this.newTag; + this.editingTag = this.newTag; + this.addNew()(this.newTag); + } + + var originalTagName = ""; + this.onTagTitleFocus = function(tag) { + originalTagName = tag.content.name; + } + + this.tagTitleDidChange = function(tag) { + this.editingTag = tag; + } + + this.saveTag = function($event, tag) { + this.editingTag = null; + if(tag.content.name.length == 0) { + tag.content.name = originalTagName; + originalTagName = ""; + return; + } + + $event.target.blur(); + if(!tag.content.name || tag.content.name.length == 0) { + return; + } + + this.save()(tag, function(savedTag){ + _.merge(tag, savedTag); + this.selectTag(tag); + this.newTag = null; + }.bind(this)); + } + + this.noteCount = function(tag) { + var validNotes = Note.filterDummyNotes(tag.notes); + return validNotes.length; + } + + this.handleDrop = function(e, newTag, note) { + this.updateNoteTag()(note, newTag, this.selectedTag); + }.bind(this) + + + }); diff --git a/app/assets/javascripts/app/frontend/models/api/item.js b/app/assets/javascripts/app/frontend/models/api/item.js index 454df0d4f..18d51ee75 100644 --- a/app/assets/javascripts/app/frontend/models/api/item.js +++ b/app/assets/javascripts/app/frontend/models/api/item.js @@ -1,6 +1,6 @@ class Item { - constructor(json_obj) { + var content; Object.defineProperty(this, "content", { @@ -12,14 +12,13 @@ class Item { if(typeof value === 'string') { try { - decodedValue = JSON.parse(value); + var decodedValue = JSON.parse(value); finalValue = decodedValue; } catch(e) { finalValue = value; } } - content = finalValue; }, enumerable: true, @@ -27,14 +26,35 @@ class Item { _.merge(this, json_obj); + if(!this.uuid) { + this.uuid = Neeto.crypto.generateUUID(); + } + this.setContentRaw = function(rawContent) { content = rawContent; } + + if(!this.content) { + this.content = {}; + } + + if(!this.content.references) { + this.content.references = []; + } + } + + addReference(reference) { + this.content.references.push(reference); + this.content.references = _.uniq(this.content.references); + } + + removeReference(reference) { + _.remove(this.content.references, _.find(this.content.references, {uuid: reference.uuid})); } referencesMatchingContentType(contentType) { - return this.references.filter(function(reference){ - return reference.content_type == content_type; + return this.content.references.filter(function(reference){ + return reference.content_type == contentType; }); } @@ -42,7 +62,7 @@ class Item { // should be overriden to manage local properties } - /* Returns true if note is shared individually or via group */ + /* Returns true if note is shared individually or via tag */ isPublic() { return this.presentation; } @@ -58,4 +78,5 @@ class Item { presentationURL() { return this.presentation.url; } + } diff --git a/app/assets/javascripts/app/frontend/models/app/note.js b/app/assets/javascripts/app/frontend/models/app/note.js index d4b7712cd..6faa9f814 100644 --- a/app/assets/javascripts/app/frontend/models/app/note.js +++ b/app/assets/javascripts/app/frontend/models/app/note.js @@ -1,33 +1,37 @@ class Note extends Item { constructor(json_obj) { - super(json_obj); - if(!this.content) { - this.content = {title: "", text: ""}; + if(!this.tags) { + this.tags = []; + } + + if(!this.content.title) { + this.content.title = ""; + this.content.text = ""; } } - filterDummyNotes(notes) { + static filterDummyNotes(notes) { var filtered = notes.filter(function(note){return note.dummy == false || note.dummy == null}); return filtered; } - get hasOnePublicGroup() { - var hasPublicGroup = false; - this.groups.forEach(function(group){ - if(group.isPublic()) { - hasPublicGroup = true; + get hasOnePublicTag() { + var hasPublicTag = false; + this.tags.forEach(function(tag){ + if(tag.isPublic()) { + hasPublicTag = true; return; } }) - return hasPublicGroup; + return hasPublicTag; } isPublic() { - return super.isPublic() || this.hasOnePublicGroup; + return super.isPublic() || this.hasOnePublicTag; } get content_type() { diff --git a/app/assets/javascripts/app/frontend/models/app/tag.js b/app/assets/javascripts/app/frontend/models/app/tag.js index 54b0a26a8..c50e9c35d 100644 --- a/app/assets/javascripts/app/frontend/models/app/tag.js +++ b/app/assets/javascripts/app/frontend/models/app/tag.js @@ -2,9 +2,23 @@ class Tag extends Item { constructor(json_obj) { super(json_obj); + + if(!this.notes) { + this.notes = []; + } + + if(!this.content.name) { + this.content.name = ""; + } } get content_type() { return "Tag"; } + + updateReferencesLocalMapping() { + super.updateReferencesLocalMapping(); + this.notes = this.referencesMatchingContentType("Note"); + console.log("notes after maping", this.notes); + } } diff --git a/app/assets/javascripts/app/frontend/routes.js b/app/assets/javascripts/app/frontend/routes.js index 33a4c25c7..864af16c2 100644 --- a/app/assets/javascripts/app/frontend/routes.js +++ b/app/assets/javascripts/app/frontend/routes.js @@ -32,7 +32,7 @@ angular.module('app.frontend') } }) - .state('group', { + .state('tag', { url: '/:root_path/:secondary_path', parent: 'base', views: { diff --git a/app/assets/javascripts/app/services/apiController.js b/app/assets/javascripts/app/services/apiController.js index 4e8f74386..7995cbfce 100644 --- a/app/assets/javascripts/app/services/apiController.js +++ b/app/assets/javascripts/app/services/apiController.js @@ -20,11 +20,15 @@ angular.module('app.frontend') } - this.$get = function(Restangular) { - return new ApiController(Restangular); + this.$get = function(Restangular, modelManager) { + return new ApiController(Restangular, modelManager); } - function ApiController(Restangular) { + function ApiController(Restangular, modelManager) { + + this.setUser = function(user) { + this.user = user; + } /* Config @@ -59,7 +63,13 @@ angular.module('app.frontend') return; } Restangular.one("users/current").get().then(function(response){ - callback(response.plain()); + var plain = response.plain(); + var items = plain.items; + this.decryptItemsWithLocalKey(items); + callback(plain); + }.bind(this)) + .catch(function(error){ + callback(null); }) } @@ -100,7 +110,7 @@ angular.module('app.frontend') if(response && !response.errors) { // this.showNewPasswordForm = false; // reencrypt data with new gk - this.reencryptAllNotesAndSave(user, new_keys.gk, current_keys.gk, function(success){ + this.reencryptAllItemsAndSave(user, new_keys.gk, current_keys.gk, function(success){ if(success) { this.setGk(new_keys.gk); alert("Your password has been changed and your data re-encrypted."); @@ -141,27 +151,27 @@ angular.module('app.frontend') } /* - Ensures that if encryption is disabled, all local notes are uncrypted, - and that if it's enabled, that all local notes are encrypted + Ensures that if encryption is disabled, all local items are uncrypted, + and that if it's enabled, that all local items are encrypted */ this.verifyEncryptionStatusOfAllItems = function(user, callback) { - var allNotes = user.filteredNotes(); - var notesNeedingUpdate = []; - allNotes.forEach(function(note){ - if(!note.isPublic()) { - if(note.encryptionEnabled() && !note.isEncrypted()) { - notesNeedingUpdate.push(note); + var allItems = user.filteredItems(); + var itemsNeedingUpdate = []; + allItems.forEach(function(item){ + if(!item.isPublic()) { + if(item.encryptionEnabled() && !item.isEncrypted()) { + itemsNeedingUpdate.push(item); } } else { - if(note.isEncrypted()) { - notesNeedingUpdate.push(note); + if(item.isEncrypted()) { + itemsNeedingUpdate.push(item); } } }.bind(this)) - if(notesNeedingUpdate.length > 0) { - console.log("verifying encryption, notes need updating", notesNeedingUpdate); - this.saveBatchNotes(user, notesNeedingUpdate, callback) + if(itemsNeedingUpdate.length > 0) { + console.log("verifying encryption, items need updating", itemsNeedingUpdate); + this.saveBatchItems(user, itemsNeedingUpdate, callback) } } @@ -176,31 +186,39 @@ angular.module('app.frontend') this.saveItems(dirtyItems, function(response){ modelManager.clearDirtyItems(); + callback(); }) } this.saveItems = function(items, callback) { - var request = Restangular.one("users", user.uuid).one("items"); + console.log("saving items", items); + var request = Restangular.one("users", this.user.uuid).one("items"); request.items = _.map(items, function(item){ - return this.createRequestParamsFromItem(item, user); + return this.createRequestParamsForItem(item); }.bind(this)); + console.log("sending request items", request.items); request.post().then(function(response) { var savedItems = response.items; - items.forEach(function(item){ - _.merge(item, _.find(savedItems, {uuid: item.uuid})); - }) + console.log("response items", savedItems); + // items.forEach(function(item) { + // _.merge(item, _.find(savedItems, {uuid: item.uuid})); + // }) callback(response); }) } - this.createRequestParamsForItem = function(item, user) { - var params = {uuid: item.uuid}; + this.createRequestParamsForItem = function(item) { + var itemCopy = _.cloneDeep(item); + + var params = {uuid: item.uuid, content_type: item.content_type}; + itemCopy.content.references = _.map(itemCopy.content.references, function(reference){ + return {uuid: reference.uuid, content_type: reference.content_type}; + }) if(!item.isPublic()) { // encrypted - var itemCopy = _.cloneDeep(item); - this.encryptSingleNote(itemCopy, this.retrieveGk()); + this.encryptSingleItem(itemCopy, this.retrieveGk()); params.content = itemCopy.content; params.loc_eek = itemCopy.loc_eek; } @@ -213,23 +231,23 @@ angular.module('app.frontend') } - this.deleteItem = function(user, item, callback) { - if(!user.id) { - this.writeUserToLocalStorage(user); + this.deleteItem = function(item, callback) { + if(!this.user.id) { + this.writeUserToLocalStorage(this.user); callback(true); } else { - Restangular.one("users", user.uuid).one("items", item.uuid).remove() + Restangular.one("users", this.user.uuid).one("items", item.uuid).remove() .then(function(response) { callback(true); }) } } - this.shareItem = function(user, item, callback) { - if(!user.id) { + this.shareItem = function(item, callback) { + if(!this.user.id) { alert("You must be signed in to share."); } else { - Restangular.one("users", user.uuid).one("items", item.uuid).one("presentations").post() + Restangular.one("users", this.user.uuid).one("items", item.uuid).one("presentations").post() .then(function(response){ var presentation = response.plain(); _.merge(item, {presentation: presentation}); @@ -237,21 +255,21 @@ angular.module('app.frontend') // decrypt references if(item.references.length > 0) { - this.saveBatchItems(user, item.references, function(success){}) + this.saveBatchItems(item.references, function(success){}) } }) } } - this.unshareItem = function(user, item, callback) { - var request = Restangular.one("users", user.uuid).one("notes", item.uuid).one("presentations", item.presentation.uuid); + this.unshareItem = function(item, callback) { + var request = Restangular.one("users", this.user.uuid).one("items", item.uuid).one("presentations", item.presentation.uuid); request.remove().then(function(response){ item.presentation = null; callback(null); // encrypt references if(item.references.length > 0) { - this.saveBatchItems(user, item.references, function(success){}) + this.saveBatchItems(item.references, function(success){}) } }) } @@ -262,7 +280,7 @@ angular.module('app.frontend') */ this.updatePresentation = function(resource, presentation, callback) { - var request = Restangular.one("users", user.id) + var request = Restangular.one("users", this.user.id) .one("items", resource.id) .one("presentations", resource.presentation.id); _.merge(request, presentation); @@ -283,24 +301,24 @@ angular.module('app.frontend') var data = JSON.parse(jsonString); var user = new User(data); console.log("importing data", JSON.parse(jsonString)); - user.notes.forEach(function(note) { - if(note.isPublic()) { - note.setContentRaw(JSON.stringify(note.content)); + user.items.forEach(function(item) { + if(item.isPublic()) { + item.setContentRaw(JSON.stringify(item.content)); } else { - this.encryptSingleNoteWithLocalKey(note); + this.encryptSingleItemWithLocalKey(item); } // prevent circular links - note.group = null; + item.tag = null; }.bind(this)) - user.groups.forEach(function(group){ + user.tags.forEach(function(tag){ // prevent circular links - group.notes = null; + tag.items = null; }) var request = Restangular.one("import"); - request.data = {notes: user.notes, groups: user.groups}; + request.data = {items: user.items, tags: user.tags}; request.post().then(function(response){ callback(true, response); }) @@ -313,7 +331,7 @@ angular.module('app.frontend') Export */ - this.notesDataFile = function(user) { + this.itemsDataFile = function(user) { var textFile = null; var makeTextFile = function (text) { var data = new Blob([text], {type: 'text/json'}); @@ -347,32 +365,32 @@ angular.module('app.frontend') } } - var notes = _.map(user.filteredNotes(), function(note){ + var items = _.map(user.filteredItems(), function(item){ return { - id: note.id, - uuid: note.uuid, - content: note.content, - group_id: note.group_id, - created_at: note.created_at, - modified_at: note.modified_at, - presentation: presentationParams(note.presentation) + id: item.id, + uuid: item.uuid, + content: item.content, + tag_id: item.tag_id, + created_at: item.created_at, + modified_at: item.modified_at, + presentation: presentationParams(item.presentation) } }); - var groups = _.map(user.groups, function(group){ + var tags = _.map(user.tags, function(tag){ return { - id: group.id, - uuid: group.uuid, - name: group.name, - created_at: group.created_at, - modified_at: group.modified_at, - presentation: presentationParams(group.presentation) + id: tag.id, + uuid: tag.uuid, + name: tag.name, + created_at: tag.created_at, + modified_at: tag.modified_at, + presentation: presentationParams(tag.presentation) } }); var data = { - notes: notes, - groups: groups + items: items, + tags: tags } return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */)); @@ -386,12 +404,12 @@ angular.module('app.frontend') */ this.mergeLocalDataRemotely = function(user, callback) { var request = Restangular.one("users", user.id).one("merge"); - var groups = user.groups; - request.notes = user.notes; - request.notes.forEach(function(note){ - if(note.group_id) { - var group = groups.filter(function(group){return group.id == note.group_id})[0]; - note.group_name = group.name; + var tags = user.tags; + request.items = user.items; + request.items.forEach(function(item){ + if(item.tag_id) { + var tag = tags.filter(function(tag){return tag.id == item.tag_id})[0]; + item.tag_name = tag.name; } }) request.post().then(function(response){ @@ -411,9 +429,9 @@ angular.module('app.frontend') this.writeUserToLocalStorage = function(user) { var saveUser = _.cloneDeep(user); - saveUser.notes = Note.filterDummyNotes(saveUser.notes); - saveUser.groups.forEach(function(group){ - group.notes = null; + saveUser.items = Item.filterDummyItems(saveUser.items); + saveUser.tags.forEach(function(tag){ + tag.items = null; }.bind(this)) this.writeToLocalStorage('user', saveUser); } @@ -425,7 +443,7 @@ angular.module('app.frontend') this.localUser = function() { var user = JSON.parse(localStorage.getItem('user')); if(!user) { - user = {notes: [], groups: []}; + user = {items: [], tags: []}; } user.shouldMerge = true; return user; @@ -436,7 +454,7 @@ angular.module('app.frontend') */ this.saveDraftToDisk = function(draft) { - localStorage.setItem("draft", JSON.stringify(draft)); + // localStorage.setItem("draft", JSON.stringify(draft)); } this.clearDraft = function() { @@ -448,7 +466,7 @@ angular.module('app.frontend') if(!draftString || draftString == 'undefined') { return null; } - return new Note(JSON.parse(draftString)); + return new Item(JSON.parse(draftString)); } @@ -472,75 +490,75 @@ angular.module('app.frontend') localStorage.removeItem("gk"); } - this.encryptSingleNote = function(note, key) { + this.encryptSingleItem = function(item, key) { var ek = null; - if(note.loc_eek) { - ek = Neeto.crypto.decryptText(note.loc_eek, key); + if(item.loc_eek) { + ek = Neeto.crypto.decryptText(item.loc_eek, key); } else { ek = Neeto.crypto.generateRandomEncryptionKey(); - note.loc_eek = Neeto.crypto.encryptText(ek, key); + item.loc_eek = Neeto.crypto.encryptText(ek, key); } - note.content = Neeto.crypto.encryptText(JSON.stringify(note.content), ek); - note.local_encryption_scheme = "1.0"; + item.content = Neeto.crypto.encryptText(JSON.stringify(item.content), ek); + item.local_encryption_scheme = "1.0"; } - this.encryptNotes = function(notes, key) { - notes.forEach(function(note){ - this.encryptSingleNote(note, key); + this.encryptItems = function(items, key) { + items.forEach(function(item){ + this.encryptSingleItem(item, key); }.bind(this)); } - this.encryptSingleNoteWithLocalKey = function(note) { - this.encryptSingleNote(note, this.retrieveGk()); + this.encryptSingleItemWithLocalKey = function(item) { + this.encryptSingleItem(item, this.retrieveGk()); } - this.encryptNotesWithLocalKey = function(notes) { - this.encryptNotes(notes, this.retrieveGk()); + this.encryptItemsWithLocalKey = function(items) { + this.encryptItems(items, this.retrieveGk()); } - this.encryptNonPublicNotesWithLocalKey = function(notes) { - var nonpublic = notes.filter(function(note){ - return !note.isPublic() && !note.pending_share; + this.encryptNonPublicItemsWithLocalKey = function(items) { + var nonpublic = items.filter(function(item){ + return !item.isPublic() && !item.pending_share; }) - this.encryptNotes(nonpublic, this.retrieveGk()); + this.encryptItems(nonpublic, this.retrieveGk()); } - this.decryptSingleNoteWithLocalKey = function(note) { - this.decryptSingleNote(note, this.retrieveGk()); + this.decryptSingleItemWithLocalKey = function(item) { + this.decryptSingleItem(item, this.retrieveGk()); } - this.decryptSingleNote = function(note, key) { - var ek = Neeto.crypto.decryptText(note.loc_eek || note.local_eek, key); - var content = Neeto.crypto.decryptText(note.content, ek); + this.decryptSingleItem = function(item, key) { + var ek = Neeto.crypto.decryptText(item.loc_eek || item.local_eek, key); + var content = Neeto.crypto.decryptText(item.content, ek); // console.log("decrypted contnet", content); - note.content = content; + item.content = content; } - this.decryptNotes = function(notes, key) { - notes.forEach(function(note){ - // console.log("is encrypted?", note); - if(note.isEncrypted()) { - this.decryptSingleNote(note, key); + this.decryptItems = function(items, key) { + items.forEach(function(item){ + // console.log("is encrypted?", item); + if(item.loc_eek && typeof item.content === 'string') { + this.decryptSingleItem(item, key); } }.bind(this)); } - this.decryptNotesWithLocalKey = function(notes) { - this.decryptNotes(notes, this.retrieveGk()); + this.decryptItemsWithLocalKey = function(items) { + this.decryptItems(items, this.retrieveGk()); } - this.reencryptAllNotesAndSave = function(user, newKey, oldKey, callback) { - var notes = user.filteredNotes(); - notes.forEach(function(note){ - if(note.isEncrypted()) { + this.reencryptAllItemsAndSave = function(user, newKey, oldKey, callback) { + var items = user.filteredItems(); + items.forEach(function(item){ + if(item.loc_eek && typeof item.content === 'string') { // first decrypt eek with old key - var ek = Neeto.crypto.decryptText(note.loc_eek, oldKey); + var ek = Neeto.crypto.decryptText(item.loc_eek, oldKey); // now encrypt ek with new key - note.loc_eek = Neeto.crypto.encryptText(ek, newKey); + item.loc_eek = Neeto.crypto.encryptText(ek, newKey); } }); - this.saveBatchNotes(user, notes, function(success) { + this.saveBatchItems(user, items, function(success) { callback(success); }.bind(this)); } diff --git a/app/assets/javascripts/app/services/directives/draggable.js b/app/assets/javascripts/app/services/directives/draggable.js index 06dd828d7..494dccc2f 100644 --- a/app/assets/javascripts/app/services/directives/draggable.js +++ b/app/assets/javascripts/app/services/directives/draggable.js @@ -41,7 +41,7 @@ angular scope: { drop: '&', bin: '=', - group: "=" + tag: "=" }, link: function(scope, element) { // again we need the native object @@ -96,7 +96,7 @@ angular scope.$apply(function(scope) { var fn = scope.drop(); if ('undefined' !== typeof fn) { - fn(e, scope.group, note); + fn(e, scope.tag, note); } }); diff --git a/app/assets/javascripts/app/services/helpers/crypto.js b/app/assets/javascripts/app/services/helpers/crypto.js index 2b786556b..1fd1ce4f2 100644 --- a/app/assets/javascripts/app/services/helpers/crypto.js +++ b/app/assets/javascripts/app/services/helpers/crypto.js @@ -6,6 +6,19 @@ Neeto.crypto = { return CryptoJS.lib.WordArray.random(256/8).toString(); }, + generateUUID: function() { + var d = new Date().getTime(); + if(window.performance && typeof window.performance.now === "function"){ + d += performance.now(); //use high-precision timer if available + } + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = (d + Math.random()*16)%16 | 0; + d = Math.floor(d/16); + return (c=='x' ? r : (r&0x3|0x8)).toString(16); + }); + return uuid; + }, + decryptText: function(encrypted_content, key) { return CryptoJS.AES.decrypt(encrypted_content, key).toString(CryptoJS.enc.Utf8); }, diff --git a/app/assets/javascripts/app/services/itemManager.js b/app/assets/javascripts/app/services/itemManager.js index 7bc1ad5c8..863b2dfab 100644 --- a/app/assets/javascripts/app/services/itemManager.js +++ b/app/assets/javascripts/app/services/itemManager.js @@ -1,8 +1,12 @@ class ItemManager { set items(items) { - this.items = items; - resolveReferences(); + this._items = items; + this.resolveReferences(); + } + + get items() { + return this._items; } referencesForItemId(itemId) { @@ -12,14 +16,14 @@ class ItemManager { resolveReferences() { this.items.forEach(function(item){ // build out references - _.map(item.references, function(reference){ - return referencesForItemId(reference.uuid); - }) - }); + item.content.references = _.map(item.content.references, function(reference){ + return this.referencesForItemId(reference.uuid); + }.bind(this)) + }.bind(this)); } itemsForContentType(contentType) { - this.items.filter(function(item){ + return this.items.filter(function(item){ return item.content_type == contentType; }); } @@ -27,22 +31,22 @@ class ItemManager { // returns dirty item references that need saving deleteItem(item) { _.remove(this.items, item); - item.references.forEach(function(referencedItem){ - removeReferencesBetweenItems(referencedItem, item); - }) + item.content.references.forEach(function(referencedItem){ + this.removeReferencesBetweenItems(referencedItem, item); + }.bind(this)) - return item.references; + return item.content.references; } removeReferencesBetweenItems(itemOne, itemTwo) { - _.remove(itemOne.references, _.find(itemOne.references, {uuid: itemTwo.uuid})); - _.remove(itemTwo.references, _.find(itemTwo.references, {uuid: itemOne.uuid})); + itemOne.removeReference(itemTwo); + itemTwo.removeReference(itemOne); return [itemOne, itemTwo]; } createReferencesBetweenItems(itemOne, itemTwo) { - itemOne.references.push(itemTwo); - itemTwo.references.push(itemOne); + itemOne.addReference(itemTwo); + itemTwo.addReference(itemOne); return [itemOne, itemTwo]; } } diff --git a/app/assets/javascripts/app/services/modelManager.js b/app/assets/javascripts/app/services/modelManager.js index 21bdbdbf0..ebe7e46b3 100644 --- a/app/assets/javascripts/app/services/modelManager.js +++ b/app/assets/javascripts/app/services/modelManager.js @@ -1,29 +1,37 @@ class ModelManager extends ItemManager { + constructor() { + super(); + this.notes = []; + this.groups = []; + this.dirtyItems = []; + } + set items(items) { super.items = items; - - this.notes = _.map(this.items.itemsForContentType("Note"), function(json_obj) { + this.notes = _.map(this.itemsForContentType("Note"), function(json_obj) { return new Note(json_obj); }) - this.groups = _.map(this.items.itemsForContentType("Group"), function(json_obj) { - var group = Group(json_obj); - group.updateReferencesLocalMapping(); - return group; + this.tags = _.map(this.itemsForContentType("Tag"), function(json_obj) { + var tag = new Tag(json_obj); + console.log("tag references upon import", tag.content.references); + tag.updateReferencesLocalMapping(); + return tag; }) } - addDirtyItems(items) { - if(this.dirtyItems) { - this.dirtyItems = []; - } - - this.dirtyItems.concat(items); + get items() { + return super.items; } - get dirtyItems() { - return this.dirtyItems || []; + addDirtyItems(items) { + if(!(items instanceof Array)) { + items = [items]; + } + + this.dirtyItems = this.dirtyItems.concat(items); + this.dirtyItems = _.uniq(this.dirtyItems); } get filteredNotes() { @@ -45,6 +53,7 @@ class ModelManager extends ItemManager { } addTagToNote(tag, note) { + console.log("adding tag to note", tag, note); var dirty = this.createReferencesBetweenItems(tag, note); this.refreshRelationshipsForTag(tag); this.refreshRelationshipsForNote(note); @@ -59,7 +68,7 @@ class ModelManager extends ItemManager { } refreshRelationshipsForNote(note) { - note.groups = note.referencesMatchingContentType("Group"); + note.tags = note.referencesMatchingContentType("Tag"); } removeTagFromNote(tag, note) { diff --git a/app/assets/stylesheets/app/_mostrap.scss b/app/assets/stylesheets/app/_mostrap.scss index f9eca65b1..c85c9f517 100644 --- a/app/assets/stylesheets/app/_mostrap.scss +++ b/app/assets/stylesheets/app/_mostrap.scss @@ -337,7 +337,7 @@ input, button, select, textarea { position: relative; } -.form-group { +.form-tag { margin-bottom: 15px; } diff --git a/app/assets/stylesheets/app/_notes.scss b/app/assets/stylesheets/app/_notes.scss index 83c9c6e60..8b0a24717 100644 --- a/app/assets/stylesheets/app/_notes.scss +++ b/app/assets/stylesheets/app/_notes.scss @@ -6,7 +6,7 @@ height: 136px !important; } - .group-menu-bar { + .tag-menu-bar { position: relative; margin: 0 -20px; width: auto; diff --git a/app/assets/stylesheets/app/_groups.scss b/app/assets/stylesheets/app/_tags.scss similarity index 92% rename from app/assets/stylesheets/app/_groups.scss rename to app/assets/stylesheets/app/_tags.scss index 152418627..06a4fee47 100644 --- a/app/assets/stylesheets/app/_groups.scss +++ b/app/assets/stylesheets/app/_tags.scss @@ -1,11 +1,11 @@ -.groups { +.tags { width: 22%; - .groups-title-bar { + .tags-title-bar { color: #0707ff; } - .group { + .tag { height: 50px; border-bottom: 1px solid $bg-color; padding: 12px; @@ -47,7 +47,7 @@ } } - /* When a note is dragged over group */ + /* When a note is dragged over tag */ &.over { background-color: rgba(#5151ff, 0.8); color: white; diff --git a/app/assets/stylesheets/frontend.css.scss b/app/assets/stylesheets/frontend.css.scss index 65405040b..89d299d4d 100644 --- a/app/assets/stylesheets/frontend.css.scss +++ b/app/assets/stylesheets/frontend.css.scss @@ -4,7 +4,7 @@ $dark-gray: #2e2e2e; @import "app/common"; @import "app/main"; @import "app/header"; -@import "app/groups"; +@import "app/tags"; @import "app/notes"; @import "app/editor"; diff --git a/app/assets/templates/frontend/auth/forgot.html.haml b/app/assets/templates/frontend/auth/forgot.html.haml index dc8c16646..cc35caa2b 100644 --- a/app/assets/templates/frontend/auth/forgot.html.haml +++ b/app/assets/templates/frontend/auth/forgot.html.haml @@ -4,7 +4,7 @@ .panel-body %p We'll send reset instructions to your email. %form{'ng-submit' => 'requestPasswordReset(forgotData)', 'ng-init' => 'forgotData = {}'} - .form-group.has-feedback + .form-tag.has-feedback %input.form-control{:autofocus => 'autofocus', :name => 'email', :placeholder => 'Email', :required => true, :type => 'email', 'ng-model' => 'forgotData.email'}/ %span.glyphicon.glyphicon-envelope.form-control-feedback .row diff --git a/app/assets/templates/frontend/auth/login.html.haml b/app/assets/templates/frontend/auth/login.html.haml index eeed98f33..29eee2529 100644 --- a/app/assets/templates/frontend/auth/login.html.haml +++ b/app/assets/templates/frontend/auth/login.html.haml @@ -3,10 +3,10 @@ %h3.panel-title Sign in to start your session .panel-body %form{'ng-submit' => 'submitLogin(loginData)', 'ng-init' => 'loginData = {}'} - .form-group.has-feedback + .form-tag.has-feedback %input.form-control{:autofocus => 'autofocus', :name => 'email', :placeholder => 'Username', :required => true, :type => 'email', 'ng-model' => 'loginData.email'}/ %span.glyphicon.glyphicon-user.form-control-feedback - .form-group.has-feedback + .form-tag.has-feedback %input.form-control{:placeholder => 'Password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'loginData.password'}/ %span.glyphicon.glyphicon-lock.form-control-feedback .row diff --git a/app/assets/templates/frontend/auth/reset.html.haml b/app/assets/templates/frontend/auth/reset.html.haml index 0fc88d22a..b50dd3a8e 100644 --- a/app/assets/templates/frontend/auth/reset.html.haml +++ b/app/assets/templates/frontend/auth/reset.html.haml @@ -4,10 +4,10 @@ .panel-body %p Type your new password. %form{'ng-submit' => 'resetPasswordSubmit()'} - .form-group.has-feedback + .form-tag.has-feedback %input.form-control{:placeholder => 'New password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'resetData.password'}/ %span.glyphicon.glyphicon-lock.form-control-feedback - .form-group.has-feedback + .form-tag.has-feedback %input.form-control{:placeholder => 'Password confirmation', :name => 'password_confirmation', :required => true, :type => 'password', 'ng-model' => 'resetData.password_confirmation'}/ %span.glyphicon.glyphicon-lock.form-control-feedback .row diff --git a/app/assets/templates/frontend/groups.html.haml b/app/assets/templates/frontend/groups.html.haml deleted file mode 100644 index 5a2917358..000000000 --- a/app/assets/templates/frontend/groups.html.haml +++ /dev/null @@ -1,16 +0,0 @@ -.section.groups - .content - .section-title-bar.groups-title-bar - .title Groups - .add-button{"ng-click" => "ctrl.clickedAddNewGroup()"} + - .group{"ng-if" => "ctrl.allGroup", "ng-click" => "ctrl.selectGroup(ctrl.allGroup)", "ng-class" => "{'selected' : ctrl.selectedGroup == ctrl.allGroup}", - "droppable" => true, "drop" => "ctrl.handleDrop", "group" => "ctrl.allGroup"} - %input.title{"ng-disabled" => "true", "ng-model" => "ctrl.allGroup.name"} - .count {{ctrl.noteCount(ctrl.allGroup)}} - .group{"ng-repeat" => "group in ctrl.groups", "ng-click" => "ctrl.selectGroup(group)", "ng-class" => "{'selected' : ctrl.selectedGroup == group}", - "droppable" => true, "drop" => "ctrl.handleDrop", "group" => "group"} - .icon.icon-rss{"ng-if" => "group.presentation"} - %input.title{"ng-disabled" => "group != ctrl.selectedGroup", "ng-model" => "group.name", - "ng-keyup" => "$event.keyCode == 13 && ctrl.saveGroup($event, group)", "mb-autofocus" => "true", "should-focus" => "ctrl.newGroup", - "ng-change" => "ctrl.groupTitleDidChange(group)", "ng-focus" => "ctrl.onGroupTitleFocus(group)"} - .count {{ctrl.noteCount(group)}} diff --git a/app/assets/templates/frontend/header.html.haml b/app/assets/templates/frontend/header.html.haml index 5edf13511..d13c71b00 100644 --- a/app/assets/templates/frontend/header.html.haml +++ b/app/assets/templates/frontend/header.html.haml @@ -20,9 +20,9 @@ .title Sign in or Register .desc %form.account-form{'name' => "loginForm"} - .form-group.has-feedback + .form-tag.has-feedback %input.form-control.login-input{:autofocus => 'autofocus', :name => 'email', :placeholder => 'Email', :required => true, :type => 'email', 'ng-model' => 'ctrl.loginData.email'} - .form-group.has-feedback + .form-tag.has-feedback %input.form-control.login-input{:placeholder => 'Password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'ctrl.loginData.user_password'} .checkbox{"ng-if" => "ctrl.hasLocalData()"} %label @@ -38,7 +38,7 @@ .panel-status-text{"ng-if" => "ctrl.loginData.status", "style" => "font-size: 14px;"} {{ctrl.loginData.status}} %form{"style" => "margin-top: 20px;", "ng-if" => "ctrl.showResetForm", "ng-init" => "ctrl.resetData = {}", 'ng-submit' => 'ctrl.forgotPasswordSubmit()', 'name' => "resetForm"} - .form-group.has-feedback + .form-tag.has-feedback %input.form-control.login-input{:autofocus => 'autofocus', :name => 'email', :placeholder => 'Email', :required => true, :type => 'email', 'ng-model' => 'ctrl.resetData.email'} %button.btn.dark-button.btn-block{:type => 'submit', "data-style" => "expand-right", "data-size" => "s", "state" => "buttonState"} %span Send Reset Email @@ -73,7 +73,7 @@ .desc Use a custom Neeto server to store and retrieve your account data. .action-container %form.account-form{'ng-submit' => 'ctrl.changeServer()', 'name' => "serverChangeForm"} - .form-group.has-feedback + .form-tag.has-feedback %input.form-control{:name => 'server', :placeholder => 'Server URL', :required => true, :type => 'text', 'ng-model' => 'ctrl.serverData.url'} %button.btn.dark-button.btn-block{:type => 'submit', "data-style" => "expand-right", "data-size" => "s", "state" => "buttonState"} %span.ladda-label Change Server @@ -82,11 +82,11 @@ .link-item %a{"ng-click" => "ctrl.changePasswordPressed()"} Change Password %form.account-form{"ng-if" => "ctrl.showNewPasswordForm", 'ng-submit' => 'ctrl.submitPasswordChange()', 'name' => "passwordChangeForm"} - .form-group.has-feedback + .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-group.has-feedback + .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-group.has-feedback + .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 diff --git a/app/assets/templates/frontend/home.html.haml b/app/assets/templates/frontend/home.html.haml index 8341b6788..00e8e81b9 100644 --- a/app/assets/templates/frontend/home.html.haml +++ b/app/assets/templates/frontend/home.html.haml @@ -2,11 +2,11 @@ %header{"user" => "defaultUser", "logout" => "headerLogout"} .app-container .app - %groups-section{"save" => "groupsSave", "add-new" => "groupsAddNew", "will-select" => "groupsWillMakeSelection", "selection-made" => "groupsSelectionMade", "all-group" => "allGroup", - "groups" => "groups", "user" => "defaultUser", "update-note-group" => "groupsUpdateNoteGroup"} + %tags-section{"save" => "tagsSave", "add-new" => "tagsAddNew", "will-select" => "tagsWillMakeSelection", "selection-made" => "tagsSelectionMade", "all-tag" => "allTag", + "tags" => "tags", "user" => "defaultUser", "update-note-tag" => "tagsUpdateNoteTag"} - %notes-section{"remove-group" => "notesRemoveGroup", "user" => "defaultUser", "add-new" => "notesAddNew", "selection-made" => "notesSelectionMade", - "group" => "selectedGroup", "user-id" => "defaultUser.id", "remove" => "deleteNote"} + %notes-section{"remove-tag" => "notesRemoveTag", "user" => "defaultUser", "add-new" => "notesAddNew", "selection-made" => "notesSelectionMade", + "tag" => "selectedTag", "user-id" => "defaultUser.id", "remove" => "deleteNote"} %editor-section{"ng-if" => "selectedNote", "note" => "selectedNote", "remove" => "deleteNote", "user" => "defaultUser", "save" => "saveNote"} diff --git a/app/assets/templates/frontend/modals/username.html.haml b/app/assets/templates/frontend/modals/username.html.haml index e7c2c34ff..b25aa3a1a 100644 --- a/app/assets/templates/frontend/modals/username.html.haml +++ b/app/assets/templates/frontend/modals/username.html.haml @@ -1,2 +1,2 @@ -%strong Choose a public username for all your shared note groups. +%strong Choose a public username for all your shared note tags. %input{"style" => "margin-top: 10px; padding-left: 8px;", "type" => "text", "ng-keyup" => "$event.keyCode == 13 && saveUsername($event)", "ng-model" => "formData.username"} diff --git a/app/assets/templates/frontend/notes.html.haml b/app/assets/templates/frontend/notes.html.haml index 0315b646a..54c8a28a9 100644 --- a/app/assets/templates/frontend/notes.html.haml +++ b/app/assets/templates/frontend/notes.html.haml @@ -1,12 +1,12 @@ .section.notes .content .section-title-bar.notes-title-bar - .title {{ctrl.group.name}} notes + .title {{ctrl.tag.name}} notes .add-button{"ng-click" => "ctrl.createNewNote()"} + %br .filter-section %input.filter-bar{"select-on-click" => "true", "ng-model" => "ctrl.noteFilter.text", "placeholder" => "Filter", "ng-change" => "ctrl.filterTextChanged()", "lowercase" => "true"} - .editor-menu.group-menu-bar + .editor-menu.tag-menu-bar %ul.nav.nav-pills %li.dropdown %a.dropdown-toggle{"ng-click" => "ctrl.showMenu = !ctrl.showMenu"} @@ -14,17 +14,17 @@ %span.caret %span.sr-only %ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark{"ng-if" => "ctrl.showMenu"} - %li{"ng-if" => "!ctrl.group.presentation"} - %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupShare($event)"} Share Group - %li{"ng-if" => "ctrl.group.presentation"} - %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupUnshare()"} Unshare Group - %li{"ng-if" => "!ctrl.group.all"} - %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedGroupDelete()"} Delete Group + %li{"ng-if" => "!ctrl.tag.presentation"} + %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagShare($event)"} Share Tag + %li{"ng-if" => "ctrl.tag.presentation"} + %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagUnshare()"} Unshare Tag + %li{"ng-if" => "!ctrl.tag.all"} + %a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagDelete()"} Delete Tag .menu-right-container - .public-link{"ng-if" => "ctrl.group.presentation"} - %a.url{"ng-if" => "!ctrl.editingUrl", "href" => "{{ctrl.publicUrlForGroup(ctrl.group)}}", "target" => "_blank"} + .public-link{"ng-if" => "ctrl.tag.presentation"} + %a.url{"ng-if" => "!ctrl.editingUrl", "href" => "{{ctrl.publicUrlForTag(ctrl.tag)}}", "target" => "_blank"} %span.icon-rss.icon - {{ctrl.publicUrlForGroup()}} + {{ctrl.publicUrlForTag()}} .edit-url{"ng-if" => "ctrl.editingUrl"} {{ctrl.url.base}} %input.input{"ng-model" => "ctrl.url.token", "ng-keyup" => "$event.keyCode == 13 && ctrl.saveUrl($event)", diff --git a/app/assets/templates/frontend/tags.html.haml b/app/assets/templates/frontend/tags.html.haml new file mode 100644 index 000000000..35de49430 --- /dev/null +++ b/app/assets/templates/frontend/tags.html.haml @@ -0,0 +1,18 @@ +.section.tags + .content + .section-title-bar.tags-title-bar + .title Tags + .add-button{"ng-click" => "ctrl.clickedAddNewTag()"} + + {{ctrl.test}} + .tag{"ng-if" => "ctrl.allTag", "ng-click" => "ctrl.selectTag(ctrl.allTag)", "ng-class" => "{'selected' : ctrl.selectedTag == ctrl.allTag}", + "droppable" => true, "drop" => "ctrl.handleDrop", "tag" => "ctrl.allTag"} + %input.title{"ng-disabled" => "true", "ng-model" => "ctrl.allTag.content.name"} + .count {{ctrl.noteCount(ctrl.allTag)}} + + .tag{"ng-repeat" => "tag in ctrl.tags", "ng-click" => "ctrl.selectTag(tag)", "ng-class" => "{'selected' : ctrl.selectedTag == tag}", + "droppable" => true, "drop" => "ctrl.handleDrop", "tag" => "tag"} + .icon.icon-rss{"ng-if" => "tag.presentation"} + %input.title{"ng-disabled" => "tag != ctrl.selectedTag", "ng-model" => "tag.content.name", + "ng-keyup" => "$event.keyCode == 13 && ctrl.saveTag($event, tag)", "mb-autofocus" => "true", "should-focus" => "ctrl.newTag", + "ng-change" => "ctrl.tagTitleDidChange(tag)", "ng-focus" => "ctrl.onTagTitleFocus(tag)"} + .count {{ctrl.noteCount(tag)}} diff --git a/vendor/assets/javascripts/transpiled.js b/vendor/assets/javascripts/transpiled.js index ff9994acd..859396d92 100644 --- a/vendor/assets/javascripts/transpiled.js +++ b/vendor/assets/javascripts/transpiled.js @@ -18,9 +18,10 @@ var Neeto = Neeto || {}; angular.module('app.frontend', ['ui.router', 'ng-token-auth', 'restangular', 'ipCookie', 'oc.lazyLoad', 'angularLazyImg', 'ngDialog']) // Configure path to API .config(function (RestangularProvider, apiControllerProvider) { + RestangularProvider.setDefaultHeaders({ "Content-Type": "application/json" }); + var url = apiControllerProvider.defaultServerURL(); RestangularProvider.setBaseUrl(url); - console.log(url); RestangularProvider.setFullRequestInterceptor(function (element, operation, route, url, headers, params, httpConfig) { var token = localStorage.getItem("jwt"); @@ -35,19 +36,7 @@ angular.module('app.frontend', ['ui.router', 'ng-token-auth', 'restangular', 'ip httpConfig: httpConfig }; }); -}); - -// Shared function for configure auth service. Can be overwritten. -function configureAuth($authProvider, apiControllerProvider) { - var url = apiControllerProvider.defaultServerURL(); - $authProvider.configure([{ - default: { - apiUrl: url, - passwordResetSuccessUrl: window.location.protocol + '//' + window.location.host + '/auth/reset' - } - }]); -} -;angular.module('app.frontend').config(function ($stateProvider, $urlRouterProvider, $locationProvider) { +});angular.module('app.frontend').config(function ($stateProvider, $urlRouterProvider, $locationProvider) { $stateProvider.state('base', { abstract: true @@ -75,7 +64,7 @@ function configureAuth($authProvider, apiControllerProvider) { resolve: { presentation: getPresentation } - }).state('group', { + }).state('tag', { url: '/:root_path/:secondary_path', parent: 'base', views: { @@ -236,11 +225,11 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); }); } }; -}).controller('EditorCtrl', function ($sce, $timeout, apiController, markdownRenderer, $rootScope) { +}).controller('EditorCtrl', function ($sce, $timeout, apiController, modelManager, markdownRenderer, $rootScope) { - this.demoNotes = [{ title: "Live print a file with tail", content: "tail -f log/production.log" }, { title: "Create SSH tunnel", content: "ssh -i .ssh/key.pem -N -L 3306:example.com:3306 ec2-user@example.com" }, { title: "List of processes running on port", content: "lsof -i:8080" }, { title: "Set ENV from file", content: "export $(cat .envfile | xargs)" }, { title: "Find process by name", content: "ps -ax | grep " }, { title: "NPM install without sudo", content: "sudo chown -R $(whoami) ~/.npm" }, { title: "Email validation regex", content: "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$" }, { title: "Ruby generate 256 bit key", content: "Digest::SHA256.hexdigest(SecureRandom.random_bytes(32))" }, { title: "Mac add user to user group", content: "sudo dseditgroup -o edit -a USERNAME -t user GROUPNAME" }, { title: "Kill Mac OS System Apache", content: "sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist" }, { title: "Docker run with mount binding and port", content: "docker run -v /home/vagrant/www/app:/var/www/app -p 8080:80 -d kpi/s3" }, { title: "MySQL grant privileges", content: "GRANT [type of permission] ON [database name].[table name] TO ‘[username]’@'%’;" }, { title: "MySQL list users", content: "SELECT User FROM mysql.user;" }]; + this.demoNotes = [{ title: "Live print a file with tail", content: "tail -f log/production.log" }, { title: "Create SSH tunnel", content: "ssh -i .ssh/key.pem -N -L 3306:example.com:3306 ec2-user@example.com" }, { title: "List of processes running on port", content: "lsof -i:8080" }, { title: "Set ENV from file", content: "export $(cat .envfile | xargs)" }, { title: "Find process by name", content: "ps -ax | grep " }, { title: "NPM install without sudo", content: "sudo chown -R $(whoami) ~/.npm" }, { title: "Email validation regex", content: "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$" }, { title: "Ruby generate 256 bit key", content: "Digest::SHA256.hexdigest(SecureRandom.random_bytes(32))" }, { title: "Mac add user to user tag", content: "sudo dsedittag -o edit -a USERNAME -t user GROUPNAME" }, { title: "Kill Mac OS System Apache", content: "sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist" }, { title: "Docker run with mount binding and port", content: "docker run -v /home/vagrant/www/app:/var/www/app -p 8080:80 -d kpi/s3" }, { title: "MySQL grant privileges", content: "GRANT [type of permission] ON [database name].[table name] TO ‘[username]’@'%’;" }, { title: "MySQL list users", content: "SELECT User FROM mysql.user;" }]; - this.showSampler = !this.user.id && this.user.filteredNotes().length == 0; + this.showSampler = !this.user.id && modelManager.filteredNotes.length == 0; this.demoNoteNames = _.map(this.demoNotes, function (note) { return note.title; @@ -448,106 +437,6 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); this.focusEditor(100); }; }); -;angular.module('app.frontend').directive("groupsSection", function () { - return { - restrict: 'E', - scope: { - addNew: "&", - selectionMade: "&", - willSelect: "&", - save: "&", - groups: "=", - allGroup: "=", - user: "=", - updateNoteGroup: "&" - }, - templateUrl: 'frontend/groups.html', - replace: true, - controller: 'GroupsCtrl', - controllerAs: 'ctrl', - bindToController: true, - - link: function link(scope, elem, attrs, ctrl) { - scope.$watch('ctrl.groups', function (newGroups) { - if (newGroups) { - ctrl.setGroups(newGroups); - } - }); - } - }; -}).controller('GroupsCtrl', function () { - - var initialLoad = true; - - this.setGroups = function (groups) { - if (initialLoad) { - initialLoad = false; - this.selectGroup(this.allGroup); - } else { - if (groups && groups.length > 0) { - this.selectGroup(groups[0]); - } - } - }; - - this.selectGroup = function (group) { - this.willSelect()(group); - this.selectedGroup = group; - this.selectionMade()(group); - }; - - this.clickedAddNewGroup = function () { - if (this.editingGroup) { - return; - } - - this.newGroup = new Group({ notes: [] }); - if (!this.user.uuid) { - this.newGroup.uuid = Neeto.crypto.generateRandomKey(); - } - this.selectedGroup = this.newGroup; - this.editingGroup = this.newGroup; - this.addNew()(this.newGroup); - }; - - var originalGroupName = ""; - this.onGroupTitleFocus = function (group) { - originalGroupName = group.name; - }; - - this.groupTitleDidChange = function (group) { - this.editingGroup = group; - }; - - this.saveGroup = function ($event, group) { - this.editingGroup = null; - if (group.name.length == 0) { - group.name = originalGroupName; - originalGroupName = ""; - return; - } - - $event.target.blur(); - if (!group.name || group.name.length == 0) { - return; - } - - this.save()(group, function (savedGroup) { - _.merge(group, savedGroup); - this.selectGroup(group); - this.newGroup = null; - }.bind(this)); - }; - - this.noteCount = function (group) { - var validNotes = Note.filterDummyNotes(group.notes); - return validNotes.length; - }; - - this.handleDrop = function (e, newGroup, note) { - this.updateNoteGroup()(note, newGroup, this.selectedGroup); - }.bind(this); -}); ;angular.module('app.frontend').directive("header", function () { return { restrict: 'E', @@ -563,7 +452,7 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); link: function link(scope, elem, attrs, ctrl) {} }; -}).controller('HeaderCtrl', function ($auth, $state, apiController, serverSideValidation, $timeout) { +}).controller('HeaderCtrl', function ($auth, $state, apiController, modelManager, serverSideValidation, $timeout) { this.changePasswordPressed = function () { this.showNewPasswordForm = !this.showNewPasswordForm; @@ -601,12 +490,12 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); }; this.hasLocalData = function () { - return this.user.filteredNotes().length > 0; + return modelManager.filteredNotes.length > 0; }; this.mergeLocalChanged = function () { if (!this.user.shouldMerge) { - if (!confirm("Unchecking this option means any locally stored groups and notes you have now will be deleted. Are you sure you want to continue?")) { + if (!confirm("Unchecking this option means any locally stored tags and notes you have now will be deleted. Are you sure you want to continue?")) { this.user.shouldMerge = true; } } @@ -650,7 +539,7 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); }; this.encryptionStatusForNotes = function () { - var allNotes = this.user.filteredNotes(); + var allNotes = modelManager.filteredNotes; var countEncrypted = 0; allNotes.forEach(function (note) { if (note.encryptionEnabled()) { @@ -705,17 +594,21 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); $rootScope.description = "A secure code box for developers to store common commands and useful notes."; var onUserSet = function onUserSet() { + apiController.setUser($scope.defaultUser); + $scope.allTag = new Tag({ all: true }); + $scope.allTag.content.name = "All"; + $scope.tags = modelManager.tags; - $scope.allGroup = new Group({ name: "All", all: true }); - $scope.groups = modelManager.groups; - - apiController.verifyEncryptionStatusOfAllItems($scope.defaultUser, function (success) {}); + // apiController.verifyEncryptionStatusOfAllItems($scope.defaultUser, function(success){}); }; apiController.getCurrentUser(function (response) { if (response && !response.errors) { + console.log("Get user response", response); $scope.defaultUser = new User(response); - modelManager.items = response.items; + modelManager.items = _.map(response.items, function (json_obj) { + return new Item(json_obj); + }); $rootScope.title = "Notes — Neeto"; onUserSet(); } else { @@ -725,44 +618,44 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); }); /* - Groups Ctrl Callbacks + Tags Ctrl Callbacks */ - $scope.updateAllGroup = function () { - $scope.allGroup.notes = modelManager.filteredNotes; + $scope.updateAllTag = function () { + $scope.allTag.notes = modelManager.filteredNotes; }; - $scope.groupsWillMakeSelection = function (group) { - if (group.all) { - $scope.updateAllGroup(); + $scope.tagsWillMakeSelection = function (tag) { + if (tag.all) { + $scope.updateAllTag(); } }; - $scope.groupsSelectionMade = function (group) { - if (!group.notes) { - group.notes = []; + $scope.tagsSelectionMade = function (tag) { + if (!tag.notes) { + tag.notes = []; } - $scope.selectedGroup = group; + $scope.selectedTag = tag; }; - $scope.groupsAddNew = function (group) { - modelManager.addTag(group); + $scope.tagsAddNew = function (tag) { + modelManager.addTag(tag); }; - $scope.groupsSave = function (group, callback) { - apiController.saveItems([group], callback); + $scope.tagsSave = function (tag, callback) { + apiController.saveItems([tag], callback); }; /* - Called to update the group of a note after drag and drop change + Called to update the tag of a note after drag and drop change The note object is a copy of the original */ - $scope.groupsUpdateNoteGroup = function (noteCopy, newGroup, oldGroup) { + $scope.tagsUpdateNoteTag = function (noteCopy, newTag, oldTag) { var originalNote = _.find($scope.defaultUser.notes, { uuid: noteCopy.uuid }); - modelManager.removeTagFromNote(oldGroup, originalNote); - if (!newGroup.all) { - modelManager.addTagToNote(newGroup, originalNote); + modelManager.removeTagFromNote(oldTag, originalNote); + if (!newTag.all) { + modelManager.addTagToNote(newTag, originalNote); } apiController.saveDirtyItems(function () {}); @@ -772,19 +665,19 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); Notes Ctrl Callbacks */ - $scope.notesRemoveGroup = function (group) { - var validNotes = Note.filterDummyNotes(group.notes); + $scope.notesRemoveTag = function (tag) { + var validNotes = Note.filterDummyNotes(tag.notes); if (validNotes == 0) { - // if no more notes, delete group - apiController.deleteItem($scope.defaultUser, group, function () { - // force scope groups to update on sub directives - $scope.groups = []; + // if no more notes, delete tag + apiController.deleteItem($scope.defaultUser, tag, function () { + // force scope tags to update on sub directives + $scope.tags = []; $timeout(function () { - $scope.groups = modelManager.groups; + $scope.tags = modelManager.tags; }); }); } else { - alert("To delete this group, remove all its notes first."); + alert("To delete this tag, remove all its notes first."); } }; @@ -793,15 +686,13 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); }; $scope.notesAddNew = function (note) { - if (!$scope.defaultUser.id) { - // generate local id for note - note.id = Neeto.crypto.generateRandomKey(); - } - modelManager.addNote(note); - if (!$scope.selectedGroup.all) { - modelManager.addTagToNote($scope.selectedGroup, note); + if (!$scope.selectedTag.all) { + console.log("add tag"); + modelManager.addTagToNote($scope.selectedTag, note); + } else { + $scope.selectedTag.notes.unshift(note); } }; @@ -810,7 +701,9 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); */ $scope.saveNote = function (note, callback) { - apiController.saveItems([note], function () { + modelManager.addDirtyItems(note); + + apiController.saveDirtyItems(function () { modelManager.addNote(note); note.hasChanges = false; @@ -842,7 +735,7 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); $scope.headerLogout = function () { $scope.defaultUser = apiController.localUser(); - $scope.groups = $scope.defaultUser.groups; + $scope.tags = $scope.defaultUser.tags; }; }); ;angular.module('app.frontend').directive("notesSection", function () { @@ -851,10 +744,11 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); addNew: "&", selectionMade: "&", remove: "&", - group: "=", + tag: "=", user: "=", - removeGroup: "&" + removeTag: "&" }, + templateUrl: 'frontend/notes.html', replace: true, controller: 'NotesCtrl', @@ -862,14 +756,14 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); bindToController: true, link: function link(scope, elem, attrs, ctrl) { - scope.$watch('ctrl.group', function (group, oldGroup) { - if (group) { - ctrl.groupDidChange(group, oldGroup); + scope.$watch('ctrl.tag', function (tag, oldTag) { + if (tag) { + ctrl.tagDidChange(tag, oldTag); } }); } }; -}).controller('NotesCtrl', function (apiController, $timeout, ngDialog, $rootScope) { +}).controller('NotesCtrl', function (apiController, modelManager, $timeout, ngDialog, $rootScope) { $rootScope.$on("editorFocused", function () { this.showMenu = false; @@ -877,15 +771,15 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); var isFirstLoad = true; - this.groupDidChange = function (group, oldGroup) { + this.tagDidChange = function (tag, oldTag) { this.showMenu = false; if (this.selectedNote && this.selectedNote.dummy) { - _.remove(oldGroup.notes, this.selectedNote); + _.remove(oldTag.notes, this.selectedNote); } this.noteFilter.text = ""; - this.setNotes(group.notes, false); + this.setNotes(tag.notes, false); if (isFirstLoad) { $timeout(function () { @@ -898,31 +792,31 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); isFirstLoad = false; } }.bind(this)); - } else if (group.notes.length == 0) { + } else if (tag.notes.length == 0) { this.createNewNote(); } }; - this.selectedGroupDelete = function () { + this.selectedTagDelete = function () { this.showMenu = false; - this.removeGroup()(this.group); + this.removeTag()(this.tag); }; - this.selectedGroupShare = function () { + this.selectedTagShare = function () { this.showMenu = false; if (!this.user.id) { - alert("You must be signed in to share a group."); + alert("You must be signed in to share a tag."); return; } - if (this.group.all) { - alert("You cannot share the 'All' group."); + if (this.tag.all) { + alert("You cannot share the 'All' tag."); return; } var _callback = function (username) { - apiController.shareItem(this.user, this.group, function (response) {}); + apiController.shareItem(this.user, this.tag, function (response) {}); }.bind(this); if (!this.user.username) { @@ -945,21 +839,21 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); } }; - this.selectedGroupUnshare = function () { + this.selectedTagUnshare = function () { this.showMenu = false; - apiController.unshareItem(this.user, this.group, function (response) {}); + apiController.unshareItem(this.user, this.tag, function (response) {}); }; - this.publicUrlForGroup = function () { - return this.group.presentation.url; + this.publicUrlForTag = function () { + return this.tag.presentation.url; }; this.setNotes = function (notes, createNew) { this.notes = notes; + console.log("set notes", notes); notes.forEach(function (note) { note.visible = true; }); - apiController.decryptNotesWithLocalKey(notes); this.selectFirstNote(createNew); }; @@ -984,7 +878,9 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); var title = "New Note" + (this.notes ? " " + (this.notes.length + 1) : ""); this.newNote = new Note({ dummy: true }); this.newNote.content.title = title; - modelManager.addTagToNote(this.group, this.newNote); + if (this.tag && !this.tag.all) { + modelManager.addTagToNote(this.tag, this.newNote); + } this.selectNote(this.newNote); this.addNew()(this.newNote); }; @@ -1008,6 +904,116 @@ angular.module('app.frontend').controller('BaseCtrl', BaseCtrl); }.bind(this), 100); }; }); +;angular.module('app.frontend').directive("tagsSection", function () { + return { + restrict: 'E', + scope: { + addNew: "&", + selectionMade: "&", + willSelect: "&", + save: "&", + tags: "=", + allTag: "=", + user: "=", + updateNoteTag: "&" + }, + templateUrl: 'frontend/tags.html', + replace: true, + controller: 'TagsCtrl', + controllerAs: 'ctrl', + bindToController: true, + + link: function link(scope, elem, attrs, ctrl) { + scope.$watch('ctrl.tags', function (newTags) { + if (newTags) { + ctrl.setTags(newTags); + } + }); + + scope.$watch('ctrl.allTag', function (allTag) { + if (allTag) { + ctrl.setAllTag(allTag); + } + }); + } + }; +}).controller('TagsCtrl', function () { + + var initialLoad = true; + + this.setAllTag = function (allTag) { + this.selectTag(this.allTag); + }; + + this.setTags = function (tags) { + if (initialLoad) { + initialLoad = false; + this.selectTag(this.allTag); + } else { + if (tags && tags.length > 0) { + this.selectTag(tags[0]); + } + } + }; + + this.selectTag = function (tag) { + this.willSelect()(tag); + this.selectedTag = tag; + this.selectionMade()(tag); + }; + + this.clickedAddNewTag = function () { + if (this.editingTag) { + return; + } + + this.newTag = new Tag({ notes: [] }); + if (!this.user.uuid) { + this.newTag.uuid = Neeto.crypto.generateRandomKey(); + } + this.selectedTag = this.newTag; + this.editingTag = this.newTag; + this.addNew()(this.newTag); + }; + + var originalTagName = ""; + this.onTagTitleFocus = function (tag) { + originalTagName = tag.content.name; + }; + + this.tagTitleDidChange = function (tag) { + this.editingTag = tag; + }; + + this.saveTag = function ($event, tag) { + this.editingTag = null; + if (tag.content.name.length == 0) { + tag.content.name = originalTagName; + originalTagName = ""; + return; + } + + $event.target.blur(); + if (!tag.content.name || tag.content.name.length == 0) { + return; + } + + this.save()(tag, function (savedTag) { + _.merge(tag, savedTag); + this.selectTag(tag); + this.newTag = null; + }.bind(this)); + }; + + this.noteCount = function (tag) { + var validNotes = Note.filterDummyNotes(tag.notes); + return validNotes.length; + }; + + this.handleDrop = function (e, newTag, note) { + this.updateNoteTag()(note, newTag, this.selectedTag); + }.bind(this); +}); ;angular.module('app.frontend').controller('UsernameModalCtrl', function ($scope, apiController, Restangular, user, callback, $timeout) { $scope.formData = {}; @@ -1036,13 +1042,12 @@ var Item = function () { if (typeof value === 'string') { try { - decodedValue = JSON.parse(value); + var decodedValue = JSON.parse(value); finalValue = decodedValue; } catch (e) { finalValue = value; } } - content = finalValue; }, enumerable: true @@ -1050,16 +1055,39 @@ var Item = function () { _.merge(this, json_obj); + if (!this.uuid) { + this.uuid = Neeto.crypto.generateUUID(); + } + this.setContentRaw = function (rawContent) { content = rawContent; }; + + if (!this.content) { + this.content = {}; + } + + if (!this.content.references) { + this.content.references = []; + } } _createClass(Item, [{ + key: 'addReference', + value: function addReference(reference) { + this.content.references.push(reference); + this.content.references = _.uniq(this.content.references); + } + }, { + key: 'removeReference', + value: function removeReference(reference) { + _.remove(this.content.references, _.find(this.content.references, { uuid: reference.uuid })); + } + }, { key: 'referencesMatchingContentType', value: function referencesMatchingContentType(contentType) { - return this.references.filter(function (reference) { - return reference.content_type == content_type; + return this.content.references.filter(function (reference) { + return reference.content_type == contentType; }); } }, { @@ -1068,7 +1096,7 @@ var Item = function () { // should be overriden to manage local properties - /* Returns true if note is shared individually or via group */ + /* Returns true if note is shared individually or via tag */ }, { key: 'isPublic', @@ -1104,13 +1132,41 @@ var Note = function (_Item) { var _this = _possibleConstructorReturn(this, (Note.__proto__ || Object.getPrototypeOf(Note)).call(this, json_obj)); - if (!_this.content) { - _this.content = { title: "", text: "" }; + if (!_this.tags) { + _this.tags = []; + } + + if (!_this.content.title) { + _this.content.title = ""; + _this.content.text = ""; } return _this; } _createClass(Note, [{ + key: 'isPublic', + value: function isPublic() { + return _get(Note.prototype.__proto__ || Object.getPrototypeOf(Note.prototype), 'isPublic', this).call(this) || this.hasOnePublicTag; + } + }, { + key: 'hasOnePublicTag', + get: function get() { + var hasPublicTag = false; + this.tags.forEach(function (tag) { + if (tag.isPublic()) { + hasPublicTag = true; + return; + } + }); + + return hasPublicTag; + } + }, { + key: 'content_type', + get: function get() { + return "Note"; + } + }], [{ key: 'filterDummyNotes', value: function filterDummyNotes(notes) { var filtered = notes.filter(function (note) { @@ -1118,29 +1174,6 @@ var Note = function (_Item) { }); return filtered; } - }, { - key: 'isPublic', - value: function isPublic() { - return _get(Note.prototype.__proto__ || Object.getPrototypeOf(Note.prototype), 'isPublic', this).call(this) || this.hasOnePublicGroup; - } - }, { - key: 'hasOnePublicGroup', - get: function get() { - var hasPublicGroup = false; - this.groups.forEach(function (group) { - if (group.isPublic()) { - hasPublicGroup = true; - return; - } - }); - - return hasPublicGroup; - } - }, { - key: 'content_type', - get: function get() { - return "Note"; - } }]); return Note; @@ -1153,10 +1186,26 @@ var Tag = function (_Item2) { function Tag(json_obj) { _classCallCheck(this, Tag); - return _possibleConstructorReturn(this, (Tag.__proto__ || Object.getPrototypeOf(Tag)).call(this, json_obj)); + var _this2 = _possibleConstructorReturn(this, (Tag.__proto__ || Object.getPrototypeOf(Tag)).call(this, json_obj)); + + if (!_this2.notes) { + _this2.notes = []; + } + + if (!_this2.content.name) { + _this2.content.name = ""; + } + return _this2; } _createClass(Tag, [{ + key: 'updateReferencesLocalMapping', + value: function updateReferencesLocalMapping() { + _get(Tag.prototype.__proto__ || Object.getPrototypeOf(Tag.prototype), 'updateReferencesLocalMapping', this).call(this); + this.notes = this.referencesMatchingContentType("Note"); + console.log("notes after maping", this.notes); + } + }, { key: 'content_type', get: function get() { return "Tag"; @@ -1193,11 +1242,15 @@ var User = function User(json_obj) { return url; }; - this.$get = function (Restangular) { - return new ApiController(Restangular); + this.$get = function (Restangular, modelManager) { + return new ApiController(Restangular, modelManager); }; - function ApiController(Restangular) { + function ApiController(Restangular, modelManager) { + + this.setUser = function (user) { + this.user = user; + }; /* Config @@ -1231,7 +1284,12 @@ var User = function User(json_obj) { return; } Restangular.one("users/current").get().then(function (response) { - callback(response.plain()); + var plain = response.plain(); + var items = plain.items; + this.decryptItemsWithLocalKey(items); + callback(plain); + }.bind(this)).catch(function (error) { + callback(null); }); }; @@ -1272,7 +1330,7 @@ var User = function User(json_obj) { if (response && !response.errors) { // this.showNewPasswordForm = false; // reencrypt data with new gk - this.reencryptAllNotesAndSave(user, new_keys.gk, current_keys.gk, function (success) { + this.reencryptAllItemsAndSave(user, new_keys.gk, current_keys.gk, function (success) { if (success) { this.setGk(new_keys.gk); alert("Your password has been changed and your data re-encrypted."); @@ -1312,27 +1370,27 @@ var User = function User(json_obj) { }; /* - Ensures that if encryption is disabled, all local notes are uncrypted, - and that if it's enabled, that all local notes are encrypted + Ensures that if encryption is disabled, all local items are uncrypted, + and that if it's enabled, that all local items are encrypted */ this.verifyEncryptionStatusOfAllItems = function (user, callback) { - var allNotes = user.filteredNotes(); - var notesNeedingUpdate = []; - allNotes.forEach(function (note) { - if (!note.isPublic()) { - if (note.encryptionEnabled() && !note.isEncrypted()) { - notesNeedingUpdate.push(note); + var allItems = user.filteredItems(); + var itemsNeedingUpdate = []; + allItems.forEach(function (item) { + if (!item.isPublic()) { + if (item.encryptionEnabled() && !item.isEncrypted()) { + itemsNeedingUpdate.push(item); } } else { - if (note.isEncrypted()) { - notesNeedingUpdate.push(note); + if (item.isEncrypted()) { + itemsNeedingUpdate.push(item); } } }.bind(this)); - if (notesNeedingUpdate.length > 0) { - console.log("verifying encryption, notes need updating", notesNeedingUpdate); - this.saveBatchNotes(user, notesNeedingUpdate, callback); + if (itemsNeedingUpdate.length > 0) { + console.log("verifying encryption, items need updating", itemsNeedingUpdate); + this.saveBatchItems(user, itemsNeedingUpdate, callback); } }; @@ -1345,31 +1403,39 @@ var User = function User(json_obj) { this.saveItems(dirtyItems, function (response) { modelManager.clearDirtyItems(); + callback(); }); }; this.saveItems = function (items, callback) { - var request = Restangular.one("users", user.uuid).one("items"); + console.log("saving items", items); + var request = Restangular.one("users", this.user.uuid).one("items"); request.items = _.map(items, function (item) { - return this.createRequestParamsFromItem(item, user); + return this.createRequestParamsForItem(item); }.bind(this)); + console.log("sending request items", request.items); request.post().then(function (response) { var savedItems = response.items; - items.forEach(function (item) { - _.merge(item, _.find(savedItems, { uuid: item.uuid })); - }); + console.log("response items", savedItems); + // items.forEach(function(item) { + // _.merge(item, _.find(savedItems, {uuid: item.uuid})); + // }) callback(response); }); }; - this.createRequestParamsForItem = function (item, user) { - var params = { uuid: item.uuid }; + this.createRequestParamsForItem = function (item) { + var itemCopy = _.cloneDeep(item); + + var params = { uuid: item.uuid, content_type: item.content_type }; + itemCopy.content.references = _.map(itemCopy.content.references, function (reference) { + return { uuid: reference.uuid, content_type: reference.content_type }; + }); if (!item.isPublic()) { // encrypted - var itemCopy = _.cloneDeep(item); - this.encryptSingleNote(itemCopy, this.retrieveGk()); + this.encryptSingleItem(itemCopy, this.retrieveGk()); params.content = itemCopy.content; params.loc_eek = itemCopy.loc_eek; } else { @@ -1380,43 +1446,43 @@ var User = function User(json_obj) { return params; }; - this.deleteItem = function (user, item, callback) { - if (!user.id) { - this.writeUserToLocalStorage(user); + this.deleteItem = function (item, callback) { + if (!this.user.id) { + this.writeUserToLocalStorage(this.user); callback(true); } else { - Restangular.one("users", user.uuid).one("items", item.uuid).remove().then(function (response) { + Restangular.one("users", this.user.uuid).one("items", item.uuid).remove().then(function (response) { callback(true); }); } }; - this.shareItem = function (user, item, callback) { - if (!user.id) { + this.shareItem = function (item, callback) { + if (!this.user.id) { alert("You must be signed in to share."); } else { - Restangular.one("users", user.uuid).one("items", item.uuid).one("presentations").post().then(function (response) { + Restangular.one("users", this.user.uuid).one("items", item.uuid).one("presentations").post().then(function (response) { var presentation = response.plain(); _.merge(item, { presentation: presentation }); callback(item); // decrypt references if (item.references.length > 0) { - this.saveBatchItems(user, item.references, function (success) {}); + this.saveBatchItems(item.references, function (success) {}); } }); } }; - this.unshareItem = function (user, item, callback) { - var request = Restangular.one("users", user.uuid).one("notes", item.uuid).one("presentations", item.presentation.uuid); + this.unshareItem = function (item, callback) { + var request = Restangular.one("users", this.user.uuid).one("items", item.uuid).one("presentations", item.presentation.uuid); request.remove().then(function (response) { item.presentation = null; callback(null); // encrypt references if (item.references.length > 0) { - this.saveBatchItems(user, item.references, function (success) {}); + this.saveBatchItems(item.references, function (success) {}); } }); }; @@ -1426,7 +1492,7 @@ var User = function User(json_obj) { */ this.updatePresentation = function (resource, presentation, callback) { - var request = Restangular.one("users", user.id).one("items", resource.id).one("presentations", resource.presentation.id); + var request = Restangular.one("users", this.user.id).one("items", resource.id).one("presentations", resource.presentation.id); _.merge(request, presentation); request.patch().then(function (response) { callback(response.plain()); @@ -1443,24 +1509,24 @@ var User = function User(json_obj) { var data = JSON.parse(jsonString); var user = new User(data); console.log("importing data", JSON.parse(jsonString)); - user.notes.forEach(function (note) { - if (note.isPublic()) { - note.setContentRaw(JSON.stringify(note.content)); + user.items.forEach(function (item) { + if (item.isPublic()) { + item.setContentRaw(JSON.stringify(item.content)); } else { - this.encryptSingleNoteWithLocalKey(note); + this.encryptSingleItemWithLocalKey(item); } // prevent circular links - note.group = null; + item.tag = null; }.bind(this)); - user.groups.forEach(function (group) { + user.tags.forEach(function (tag) { // prevent circular links - group.notes = null; + tag.items = null; }); var request = Restangular.one("import"); - request.data = { notes: user.notes, groups: user.groups }; + request.data = { items: user.items, tags: user.tags }; request.post().then(function (response) { callback(true, response); }).catch(function (error) { @@ -1472,7 +1538,7 @@ var User = function User(json_obj) { Export */ - this.notesDataFile = function (user) { + this.itemsDataFile = function (user) { var textFile = null; var makeTextFile = function (text) { var data = new Blob([text], { type: 'text/json' }); @@ -1506,32 +1572,32 @@ var User = function User(json_obj) { }; }; - var notes = _.map(user.filteredNotes(), function (note) { + var items = _.map(user.filteredItems(), function (item) { return { - id: note.id, - uuid: note.uuid, - content: note.content, - group_id: note.group_id, - created_at: note.created_at, - modified_at: note.modified_at, - presentation: presentationParams(note.presentation) + id: item.id, + uuid: item.uuid, + content: item.content, + tag_id: item.tag_id, + created_at: item.created_at, + modified_at: item.modified_at, + presentation: presentationParams(item.presentation) }; }); - var groups = _.map(user.groups, function (group) { + var tags = _.map(user.tags, function (tag) { return { - id: group.id, - uuid: group.uuid, - name: group.name, - created_at: group.created_at, - modified_at: group.modified_at, - presentation: presentationParams(group.presentation) + id: tag.id, + uuid: tag.uuid, + name: tag.name, + created_at: tag.created_at, + modified_at: tag.modified_at, + presentation: presentationParams(tag.presentation) }; }); var data = { - notes: notes, - groups: groups + items: items, + tags: tags }; return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */)); @@ -1542,14 +1608,14 @@ var User = function User(json_obj) { */ this.mergeLocalDataRemotely = function (user, callback) { var request = Restangular.one("users", user.id).one("merge"); - var groups = user.groups; - request.notes = user.notes; - request.notes.forEach(function (note) { - if (note.group_id) { - var group = groups.filter(function (group) { - return group.id == note.group_id; + var tags = user.tags; + request.items = user.items; + request.items.forEach(function (item) { + if (item.tag_id) { + var tag = tags.filter(function (tag) { + return tag.id == item.tag_id; })[0]; - note.group_name = group.name; + item.tag_name = tag.name; } }); request.post().then(function (response) { @@ -1564,9 +1630,9 @@ var User = function User(json_obj) { this.writeUserToLocalStorage = function (user) { var saveUser = _.cloneDeep(user); - saveUser.notes = Note.filterDummyNotes(saveUser.notes); - saveUser.groups.forEach(function (group) { - group.notes = null; + saveUser.items = Item.filterDummyItems(saveUser.items); + saveUser.tags.forEach(function (tag) { + tag.items = null; }.bind(this)); this.writeToLocalStorage('user', saveUser); }; @@ -1578,7 +1644,7 @@ var User = function User(json_obj) { this.localUser = function () { var user = JSON.parse(localStorage.getItem('user')); if (!user) { - user = { notes: [], groups: [] }; + user = { items: [], tags: [] }; } user.shouldMerge = true; return user; @@ -1589,7 +1655,7 @@ var User = function User(json_obj) { */ this.saveDraftToDisk = function (draft) { - localStorage.setItem("draft", JSON.stringify(draft)); + // localStorage.setItem("draft", JSON.stringify(draft)); }; this.clearDraft = function () { @@ -1601,7 +1667,7 @@ var User = function User(json_obj) { if (!draftString || draftString == 'undefined') { return null; } - return new Note(JSON.parse(draftString)); + return new Item(JSON.parse(draftString)); }; /* @@ -1624,82 +1690,81 @@ var User = function User(json_obj) { localStorage.removeItem("gk"); }; - this.encryptSingleNote = function (note, key) { + this.encryptSingleItem = function (item, key) { var ek = null; - if (note.loc_eek) { - ek = Neeto.crypto.decryptText(note.loc_eek, key); + if (item.loc_eek) { + ek = Neeto.crypto.decryptText(item.loc_eek, key); } else { ek = Neeto.crypto.generateRandomEncryptionKey(); - note.loc_eek = Neeto.crypto.encryptText(ek, key); + item.loc_eek = Neeto.crypto.encryptText(ek, key); } - note.content = Neeto.crypto.encryptText(JSON.stringify(note.content), ek); - note.local_encryption_scheme = "1.0"; + item.content = Neeto.crypto.encryptText(JSON.stringify(item.content), ek); + item.local_encryption_scheme = "1.0"; }; - this.encryptNotes = function (notes, key) { - notes.forEach(function (note) { - this.encryptSingleNote(note, key); + this.encryptItems = function (items, key) { + items.forEach(function (item) { + this.encryptSingleItem(item, key); }.bind(this)); }; - this.encryptSingleNoteWithLocalKey = function (note) { - this.encryptSingleNote(note, this.retrieveGk()); + this.encryptSingleItemWithLocalKey = function (item) { + this.encryptSingleItem(item, this.retrieveGk()); }; - this.encryptNotesWithLocalKey = function (notes) { - this.encryptNotes(notes, this.retrieveGk()); + this.encryptItemsWithLocalKey = function (items) { + this.encryptItems(items, this.retrieveGk()); }; - this.encryptNonPublicNotesWithLocalKey = function (notes) { - var nonpublic = notes.filter(function (note) { - return !note.isPublic() && !note.pending_share; + this.encryptNonPublicItemsWithLocalKey = function (items) { + var nonpublic = items.filter(function (item) { + return !item.isPublic() && !item.pending_share; }); - this.encryptNotes(nonpublic, this.retrieveGk()); + this.encryptItems(nonpublic, this.retrieveGk()); }; - this.decryptSingleNoteWithLocalKey = function (note) { - this.decryptSingleNote(note, this.retrieveGk()); + this.decryptSingleItemWithLocalKey = function (item) { + this.decryptSingleItem(item, this.retrieveGk()); }; - this.decryptSingleNote = function (note, key) { - var ek = Neeto.crypto.decryptText(note.loc_eek || note.local_eek, key); - var content = Neeto.crypto.decryptText(note.content, ek); + this.decryptSingleItem = function (item, key) { + var ek = Neeto.crypto.decryptText(item.loc_eek || item.local_eek, key); + var content = Neeto.crypto.decryptText(item.content, ek); // console.log("decrypted contnet", content); - note.content = content; + item.content = content; }; - this.decryptNotes = function (notes, key) { - notes.forEach(function (note) { - // console.log("is encrypted?", note); - if (note.isEncrypted()) { - this.decryptSingleNote(note, key); + this.decryptItems = function (items, key) { + items.forEach(function (item) { + // console.log("is encrypted?", item); + if (item.loc_eek && typeof item.content === 'string') { + this.decryptSingleItem(item, key); } }.bind(this)); }; - this.decryptNotesWithLocalKey = function (notes) { - this.decryptNotes(notes, this.retrieveGk()); + this.decryptItemsWithLocalKey = function (items) { + this.decryptItems(items, this.retrieveGk()); }; - this.reencryptAllNotesAndSave = function (user, newKey, oldKey, callback) { - var notes = user.filteredNotes(); - notes.forEach(function (note) { - if (note.isEncrypted()) { + this.reencryptAllItemsAndSave = function (user, newKey, oldKey, callback) { + var items = user.filteredItems(); + items.forEach(function (item) { + if (item.loc_eek && typeof item.content === 'string') { // first decrypt eek with old key - var ek = Neeto.crypto.decryptText(note.loc_eek, oldKey); + var ek = Neeto.crypto.decryptText(item.loc_eek, oldKey); // now encrypt ek with new key - note.loc_eek = Neeto.crypto.encryptText(ek, newKey); + item.loc_eek = Neeto.crypto.encryptText(ek, newKey); } }); - this.saveBatchNotes(user, notes, function (success) { + this.saveBatchItems(user, items, function (success) { callback(success); }.bind(this)); }; } }); ; - var ItemManager = function () { function ItemManager() { _classCallCheck(this, ItemManager); @@ -1715,15 +1780,15 @@ var ItemManager = function () { value: function resolveReferences() { this.items.forEach(function (item) { // build out references - _.map(item.references, function (reference) { - return referencesForItemId(reference.uuid); - }); - }); + item.content.references = _.map(item.content.references, function (reference) { + return this.referencesForItemId(reference.uuid); + }.bind(this)); + }.bind(this)); } }, { key: 'itemsForContentType', value: function itemsForContentType(contentType) { - this.items.filter(function (item) { + return this.items.filter(function (item) { return item.content_type == contentType; }); } @@ -1734,31 +1799,34 @@ var ItemManager = function () { key: 'deleteItem', value: function deleteItem(item) { _.remove(this.items, item); - item.references.forEach(function (referencedItem) { - removeReferencesBetweenItems(referencedItem, item); - }); + item.content.references.forEach(function (referencedItem) { + this.removeReferencesBetweenItems(referencedItem, item); + }.bind(this)); - return item.references; + return item.content.references; } }, { key: 'removeReferencesBetweenItems', value: function removeReferencesBetweenItems(itemOne, itemTwo) { - _.remove(itemOne.references, _.find(itemOne.references, { uuid: itemTwo.uuid })); - _.remove(itemTwo.references, _.find(itemTwo.references, { uuid: itemOne.uuid })); + itemOne.removeReference(itemTwo); + itemTwo.removeReference(itemOne); return [itemOne, itemTwo]; } }, { key: 'createReferencesBetweenItems', value: function createReferencesBetweenItems(itemOne, itemTwo) { - itemOne.references.push(itemTwo); - itemTwo.references.push(itemOne); + itemOne.addReference(itemTwo); + itemTwo.addReference(itemOne); return [itemOne, itemTwo]; } }, { key: 'items', set: function set(items) { - this.items = items; - resolveReferences(); + this._items = items; + this.resolveReferences(); + }, + get: function get() { + return this._items; } }]); @@ -1791,17 +1859,23 @@ var ModelManager = function (_ItemManager) { function ModelManager() { _classCallCheck(this, ModelManager); - return _possibleConstructorReturn(this, (ModelManager.__proto__ || Object.getPrototypeOf(ModelManager)).apply(this, arguments)); + var _this3 = _possibleConstructorReturn(this, (ModelManager.__proto__ || Object.getPrototypeOf(ModelManager)).call(this)); + + _this3.notes = []; + _this3.groups = []; + _this3.dirtyItems = []; + return _this3; } _createClass(ModelManager, [{ key: 'addDirtyItems', value: function addDirtyItems(items) { - if (this.dirtyItems) { - this.dirtyItems = []; + if (!(items instanceof Array)) { + items = [items]; } - this.dirtyItems.concat(items); + this.dirtyItems = this.dirtyItems.concat(items); + this.dirtyItems = _.uniq(this.dirtyItems); } }, { key: 'clearDirtyItems', @@ -1823,6 +1897,7 @@ var ModelManager = function (_ItemManager) { }, { key: 'addTagToNote', value: function addTagToNote(tag, note) { + console.log("adding tag to note", tag, note); var dirty = this.createReferencesBetweenItems(tag, note); this.refreshRelationshipsForTag(tag); this.refreshRelationshipsForNote(note); @@ -1839,7 +1914,7 @@ var ModelManager = function (_ItemManager) { }, { key: 'refreshRelationshipsForNote', value: function refreshRelationshipsForNote(note) { - note.groups = note.referencesMatchingContentType("Group"); + note.tags = note.referencesMatchingContentType("Tag"); } }, { key: 'removeTagFromNote', @@ -1868,21 +1943,19 @@ var ModelManager = function (_ItemManager) { key: 'items', set: function set(items) { _set(ModelManager.prototype.__proto__ || Object.getPrototypeOf(ModelManager.prototype), 'items', items, this); - - this.notes = _.map(this.items.itemsForContentType("Note"), function (json_obj) { + this.notes = _.map(this.itemsForContentType("Note"), function (json_obj) { return new Note(json_obj); }); - this.groups = _.map(this.items.itemsForContentType("Group"), function (json_obj) { - var group = Group(json_obj); - group.updateReferencesLocalMapping(); - return group; + this.tags = _.map(this.itemsForContentType("Tag"), function (json_obj) { + var tag = new Tag(json_obj); + console.log("tag references upon import", tag.content.references); + tag.updateReferencesLocalMapping(); + return tag; }); - } - }, { - key: 'dirtyItems', + }, get: function get() { - return this.dirtyItems || []; + return _get(ModelManager.prototype.__proto__ || Object.getPrototypeOf(ModelManager.prototype), 'items', this); } }, { key: 'filteredNotes', @@ -1960,7 +2033,7 @@ angular.module('app.frontend').directive('droppable', function () { scope: { drop: '&', bin: '=', - group: "=" + tag: "=" }, link: function link(scope, element) { // again we need the native object @@ -2001,7 +2074,7 @@ angular.module('app.frontend').directive('droppable', function () { scope.$apply(function (scope) { var fn = scope.drop(); if ('undefined' !== typeof fn) { - fn(e, scope.group, note); + fn(e, scope.tag, note); } }); @@ -2263,6 +2336,19 @@ Neeto.crypto = { return CryptoJS.lib.WordArray.random(256 / 8).toString(); }, + generateUUID: function generateUUID() { + var d = new Date().getTime(); + if (window.performance && typeof window.performance.now === "function") { + d += performance.now(); //use high-precision timer if available + } + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c == 'x' ? r : r & 0x3 | 0x8).toString(16); + }); + return uuid; + }, + decryptText: function decryptText(encrypted_content, key) { return CryptoJS.AES.decrypt(encrypted_content, key).toString(CryptoJS.enc.Utf8); }, diff --git a/vendor/assets/javascripts/transpiled.js.map b/vendor/assets/javascripts/transpiled.js.map index 715ef7496..ec86c160a 100644 --- a/vendor/assets/javascripts/transpiled.js.map +++ b/vendor/assets/javascripts/transpiled.js.map @@ -1 +1 @@ -{"version":3,"sources":["app.js"],"names":["Neeto","angular","module","config","RestangularProvider","apiControllerProvider","url","defaultServerURL","setBaseUrl","console","log","setFullRequestInterceptor","element","operation","route","headers","params","httpConfig","token","localStorage","getItem","_","extend","Authorization","configureAuth","$authProvider","configure","default","apiUrl","passwordResetSuccessUrl","window","location","protocol","host","$stateProvider","$urlRouterProvider","$locationProvider","state","abstract","parent","views","templateUrl","controller","resolve","presentation","getPresentation","$rootScope","$stateParams","resetData","reset_password_token","email","$on","event","toState","toParams","fromState","fromParams","options","$q","$state","Restangular","deferred","defer","restangularQuery","one","get","root_path","secondary_path","then","response","catch","go","promise","otherwise","$injector","$location","path","html5Mode","BaseCtrl","modelManager","directive","$timeout","restrict","scope","save","remove","note","user","replace","controllerAs","bindToController","link","elem","attrs","ctrl","handler","ctrlKey","metaKey","String","fromCharCode","which","toLowerCase","preventDefault","saveNote","clickedEditNote","toggleMarkdown","toggleFullScreen","addEventListener","removeEventListener","$watch","oldNote","setNote","$sce","apiController","markdownRenderer","demoNotes","title","content","showSampler","id","filteredNotes","length","demoNoteNames","map","currentDemoContent","text","prebeginFn","bind","callback","index","contentCallback","editorMode","focusTitle","hasChanges","dummy","onPreviewDoubleClick","focusEditor","delay","setTimeout","document","getElementById","focus","clickedTextArea","showMenu","renderedContent","renderHtml","renderedContentForText","statusTimeout","$event","success","clearDraft","cancel","noteStatus","saveTitle","target","blur","saveTimeout","changesMade","saveDraftToDisk","contentChanged","nameChanged","onNameFocus","editingName","onContentFocus","$broadcast","editingUrl","onNameBlur","fullscreen","selectedMenuItem","editUrlPressed","publicUrlForNote","base","saveUrl","original","relative_path","updatePresentation","alert","shareNote","openInNewTab","a","createElement","href","click","shareItem","unshareNote","unshareItem","presentationURL","clickedMenu","locked","deleteNote","addNew","selectionMade","willSelect","groups","allGroup","updateNoteGroup","newGroups","setGroups","initialLoad","selectGroup","group","selectedGroup","clickedAddNewGroup","editingGroup","newGroup","Group","notes","uuid","crypto","generateRandomKey","originalGroupName","onGroupTitleFocus","name","groupTitleDidChange","saveGroup","savedGroup","merge","noteCount","validNotes","Note","filterDummyNotes","handleDrop","e","logout","$auth","serverSideValidation","changePasswordPressed","showNewPasswordForm","accountMenuPressed","serverData","getServer","showAccountMenu","showFaq","changeServer","setServer","signOutPressed","signout","reload","submitPasswordChange","passwordChangeData","status","data","password","password_confirmation","changePassword","current_password","new_password","hasLocalData","mergeLocalChanged","shouldMerge","confirm","loginSubmitPressed","loginData","login","user_password","errors","onAuthSuccess","submitRegistrationForm","register","forgotPasswordSubmit","requestPasswordReset","resp","encryptionStatusForNotes","allNotes","countEncrypted","forEach","encryptionEnabled","downloadDataArchive","setAttribute","notesDataFile","importFileSelected","files","file","reader","FileReader","onload","importJSONData","result","readAsText","mergeLocalDataRemotely","showLogin","showRegistration","$scope","bodyClass","description","onUserSet","all","verifyEncryptionStatusOfAllItems","defaultUser","getCurrentUser","User","items","localUser","updateAllGroup","groupsWillMakeSelection","groupsSelectionMade","groupsAddNew","addTag","groupsSave","saveItems","groupsUpdateNoteGroup","noteCopy","oldGroup","originalNote","find","removeTagFromNote","addTagToNote","saveDirtyItems","notesRemoveGroup","deleteItem","notesSelectionMade","selectedNote","notesAddNew","addNote","headerLogout","removeGroup","groupDidChange","ngDialog","isFirstLoad","noteFilter","setNotes","draft","getDraft","selectNote","createNewNote","selectedGroupDelete","selectedGroupShare","username","open","template","className","disableAnimation","selectedGroupUnshare","publicUrlForGroup","createNew","visible","decryptNotesWithLocalKey","selectFirstNote","visibleNotes","filter","newNote","filterNotes","includes","filterTextChanged","formData","saveUsername","setUsername","closeThisDialog","Item","json_obj","Object","defineProperty","set","value","finalValue","decodedValue","JSON","parse","enumerable","setContentRaw","rawContent","contentType","references","reference","content_type","loc_eek","filtered","hasOnePublicGroup","hasPublicGroup","isPublic","Tag","provider","domainName","domain_comps","hostname","split","domain","port","$get","ApiController","refresh","setItem","plain","keys","generateEncryptionKeysForUser","setGk","gk","request","pw","post","current_keys","new_keys","_performPasswordChange","reencryptAllNotesAndSave","patch","notesNeedingUpdate","isEncrypted","push","saveBatchNotes","dirtyItems","clearDirtyItems","item","createRequestParamsFromItem","savedItems","createRequestParamsForItem","itemCopy","cloneDeep","encryptSingleNote","retrieveGk","stringify","writeUserToLocalStorage","saveBatchItems","resource","error","nil","jsonString","encryptSingleNoteWithLocalKey","textFile","makeTextFile","Blob","type","URL","revokeObjectURL","createObjectURL","presentationParams","presentable_type","presentable_id","created_at","modified_at","group_id","group_name","removeItem","staticifyObject","object","saveUser","writeToLocalStorage","key","toJson","draftString","ek","decryptText","generateRandomEncryptionKey","encryptText","local_encryption_scheme","encryptNotes","encryptNotesWithLocalKey","encryptNonPublicNotesWithLocalKey","nonpublic","pending_share","decryptSingleNoteWithLocalKey","decryptSingleNote","local_eek","decryptNotes","newKey","oldKey","ItemManager","itemId","referencesForItemId","referencedItem","removeReferencesBetweenItems","itemOne","itemTwo","resolveReferences","service","marked","setOptions","breaks","sanitize","html_code","trustAsHtml","ModelManager","concat","unshift","tag","tags","dirty","createReferencesBetweenItems","refreshRelationshipsForTag","refreshRelationshipsForNote","addDirtyItems","referencesMatchingContentType","sort","b","Date","itemsForContentType","updateReferencesLocalMapping","showErrors","formErrors","form","$setDirty","$setValidity","$error","server","join","parseErrors","shouldFocus","$element","el","draggable","dataTransfer","effectAllowed","setData","classList","add","drop","bin","dropEffect","counter","stopPropagation","binId","getData","$apply","fn","on","require","modelCtrl","lowercase","inputValue","undefined","lowercased","$setViewValue","$render","$parsers","ngModel","$window","getSelection","toString","setSelectionRange","linkFunction","$attrs","timer","initialDelay","getTypeDelay","typeDelay","eraseDelay","blinkDelay","getAnimationDelay","cursor","blinkCursor","currentText","textArray","running","auxStyle","Array","start","typewrite","updateIt","charIndex","arrIndex","updateValue","substring","iterationCallback","cleanAndRestart","iterationDelay","callbackFn","blinkIt","slice","charAt","parseInt","prop","toUpperCase","val","html","newVal","oldVal","CryptoJS","lib","WordArray","random","encrypted_content","AES","decrypt","enc","Utf8","encrypt","salt","passphrase","PBKDF2","keySize","sha256","SHA256","generateAsymmetricKeyPair","input","output","hasher","algo","SHA512","iterations","firstHalf","clone","secondHalf","sigBytes","outputLength","words"],"mappings":"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","file":"transpiled.js","sourcesContent":["'use strict';\n\nvar Neeto = Neeto || {};\n\nangular\n .module('app.frontend', [\n 'ui.router',\n 'ng-token-auth',\n 'restangular',\n 'ipCookie',\n 'oc.lazyLoad',\n 'angularLazyImg',\n 'ngDialog'\n ])\n // Configure path to API\n .config(function (RestangularProvider, apiControllerProvider) {\n var url = apiControllerProvider.defaultServerURL();\n RestangularProvider.setBaseUrl(url);\n console.log(url);\n\n RestangularProvider.setFullRequestInterceptor(function(element, operation, route, url, headers, params, httpConfig) {\n var token = localStorage.getItem(\"jwt\");\n if(token) {\n headers = _.extend(headers, {Authorization: \"Bearer \" + localStorage.getItem(\"jwt\")});\n }\n\n return {\n element: element,\n params: params,\n headers: headers,\n httpConfig: httpConfig\n };\n });\n })\n\n // Shared function for configure auth service. Can be overwritten.\n function configureAuth ($authProvider, apiControllerProvider) {\n var url = apiControllerProvider.defaultServerURL();\n $authProvider.configure([{\n default: {\n apiUrl: url,\n passwordResetSuccessUrl: window.location.protocol + '//' + window.location.host + '/auth/reset',\n }\n }]);\n }\n;angular.module('app.frontend')\n .config(function ($stateProvider, $urlRouterProvider, $locationProvider) {\n\n $stateProvider\n .state('base', {\n abstract: true,\n })\n\n // Homepage\n .state('home', {\n url: '/',\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/home.html',\n controller: 'HomeCtrl'\n }\n }\n })\n\n .state('presentation', {\n url: '/:root_path',\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/presentation.html',\n controller: \"PresentationCtrl\"\n }\n },\n resolve: {\n presentation: getPresentation\n }\n })\n\n .state('group', {\n url: '/:root_path/:secondary_path',\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/presentation.html',\n controller: \"PresentationCtrl\"\n }\n },\n resolve: {\n presentation: getPresentation\n }\n })\n\n // Auth routes\n .state('auth', {\n abstract: true,\n url: '/auth',\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/auth/wrapper.html',\n }\n }\n })\n .state('auth.login', {\n url: '/login',\n templateUrl: 'frontend/auth/login.html',\n })\n .state('auth.forgot', {\n url: '/forgot',\n templateUrl: 'frontend/auth/forgot.html',\n })\n .state('auth.reset', {\n url: '/reset?reset_password_token&email',\n templateUrl: 'frontend/auth/reset.html',\n controller: function($rootScope, $stateParams) {\n $rootScope.resetData = {reset_password_token: $stateParams.reset_password_token, email: $stateParams.email};\n\n // Clear reset_password_token on change state\n $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options) {\n $rootScope.reset_password_token = null;\n });\n },\n })\n\n\n // 404 Error\n .state('404', {\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/errors/404.html'\n }\n }\n });\n\n function getPresentation ($q, $state, $stateParams, Restangular) {\n var deferred = $q.defer();\n var restangularQuery = Restangular.one('presentations', 'show_by_path');\n restangularQuery.get({root_path: $stateParams.root_path, secondary_path: $stateParams.secondary_path})\n .then(function(response) {\n deferred.resolve(response);\n })\n .catch(function(response) {\n $state.go('404');\n });\n\n return deferred.promise;\n }\n\n // Default fall back route\n $urlRouterProvider.otherwise(function($injector, $location){\n var state = $injector.get('$state');\n state.go('404');\n return $location.path();\n });\n\n // enable HTML5 Mode for SEO\n $locationProvider.html5Mode(true);\n\n });\n;class BaseCtrl {\n constructor($rootScope, modelManager) {\n // $rootScope.resetPasswordSubmit = function() {\n // var new_keys = Neeto.crypto.generateEncryptionKeysForUser($rootScope.resetData.password, $rootScope.resetData.email);\n // var data = _.clone($rootScope.resetData);\n // data.password = new_keys.pw;\n // data.password_confirmation = new_keys.pw;\n // $auth.updatePassword(data);\n // apiController.setGk(new_keys.gk);\n // }\n\n // var note = new Note();\n // note.content = {title: \"hello\", text: \"world\"};\n // console.log(\"note content\", note.content);\n // console.log(\"note title\", note.title);\n // console.log(\"note json\", JSON.stringify(note));\n //\n // console.log(\"Copy\", _.cloneDeep(note));\n }\n}\n\nangular.module('app.frontend').controller('BaseCtrl', BaseCtrl);\n;angular.module('app.frontend')\n .directive(\"editorSection\", function($timeout){\n return {\n restrict: 'E',\n scope: {\n save: \"&\",\n remove: \"&\",\n note: \"=\",\n user: \"=\"\n },\n templateUrl: 'frontend/editor.html',\n replace: true,\n controller: 'EditorCtrl',\n controllerAs: 'ctrl',\n bindToController: true,\n\n link:function(scope, elem, attrs, ctrl) {\n\n var handler = function(event) {\n if (event.ctrlKey || event.metaKey) {\n switch (String.fromCharCode(event.which).toLowerCase()) {\n case 's':\n event.preventDefault();\n $timeout(function(){\n ctrl.saveNote(event);\n });\n break;\n case 'e':\n event.preventDefault();\n $timeout(function(){\n ctrl.clickedEditNote();\n })\n break;\n case 'm':\n event.preventDefault();\n $timeout(function(){\n ctrl.toggleMarkdown();\n })\n break;\n case 'o':\n event.preventDefault();\n $timeout(function(){\n ctrl.toggleFullScreen();\n })\n break;\n }\n }\n };\n\n window.addEventListener('keydown', handler);\n\n scope.$on('$destroy', function(){\n window.removeEventListener('keydown', handler);\n })\n\n scope.$watch('ctrl.note', function(note, oldNote){\n if(note) {\n ctrl.setNote(note, oldNote);\n } else {\n ctrl.note = {};\n }\n });\n }\n }\n })\n .controller('EditorCtrl', function ($sce, $timeout, apiController, markdownRenderer, $rootScope) {\n\n this.demoNotes = [\n {title: \"Live print a file with tail\", content: \"tail -f log/production.log\"},\n {title: \"Create SSH tunnel\", content: \"ssh -i .ssh/key.pem -N -L 3306:example.com:3306 ec2-user@example.com\"},\n {title: \"List of processes running on port\", content: \"lsof -i:8080\"},\n {title: \"Set ENV from file\", content: \"export $(cat .envfile | xargs)\"},\n {title: \"Find process by name\", content: \"ps -ax | grep \"},\n {title: \"NPM install without sudo\", content: \"sudo chown -R $(whoami) ~/.npm\"},\n {title: \"Email validation regex\", content: \"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$\"},\n {title: \"Ruby generate 256 bit key\", content: \"Digest::SHA256.hexdigest(SecureRandom.random_bytes(32))\"},\n {title: \"Mac add user to user group\", content: \"sudo dseditgroup -o edit -a USERNAME -t user GROUPNAME\"},\n {title: \"Kill Mac OS System Apache\", content: \"sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist\"},\n {title: \"Docker run with mount binding and port\", content: \"docker run -v /home/vagrant/www/app:/var/www/app -p 8080:80 -d kpi/s3\"},\n {title: \"MySQL grant privileges\", content: \"GRANT [type of permission] ON [database name].[table name] TO ‘[username]’@'%’;\"},\n {title: \"MySQL list users\", content: \"SELECT User FROM mysql.user;\"},\n ];\n\n this.showSampler = !this.user.id && this.user.filteredNotes().length == 0;\n\n this.demoNoteNames = _.map(this.demoNotes, function(note){\n return note.title;\n });\n\n this.currentDemoContent = {text: null};\n\n this.prebeginFn = function() {\n this.currentDemoContent.text = null;\n }.bind(this)\n\n this.callback = function(index) {\n this.currentDemoContent.text = this.demoNotes[index].text;\n }.bind(this)\n\n this.contentCallback = function(index) {\n }\n\n this.setNote = function(note, oldNote) {\n this.editorMode = 'edit';\n if(note.content.text.length == 0) {\n this.focusTitle(100);\n }\n\n if(oldNote && oldNote != note) {\n if(oldNote.hasChanges) {\n this.save()(oldNote, null);\n } else if(oldNote.dummy) {\n this.remove()(oldNote);\n }\n }\n }\n\n this.onPreviewDoubleClick = function() {\n this.editorMode = 'edit';\n this.focusEditor(100);\n }\n\n this.focusEditor = function(delay) {\n setTimeout(function(){\n var element = document.getElementById(\"note-text-editor\");\n element.focus();\n }, delay)\n }\n\n this.focusTitle = function(delay) {\n setTimeout(function(){\n document.getElementById(\"note-title-editor\").focus();\n }, delay)\n }\n\n this.clickedTextArea = function() {\n this.showMenu = false;\n }\n\n this.renderedContent = function() {\n return markdownRenderer.renderHtml(markdownRenderer.renderedContentForText(this.note.content.text));\n }\n\n var statusTimeout;\n\n this.saveNote = function($event) {\n var note = this.note;\n note.dummy = false;\n this.save()(note, function(success){\n if(success) {\n apiController.clearDraft();\n\n if(statusTimeout) $timeout.cancel(statusTimeout);\n statusTimeout = $timeout(function(){\n this.noteStatus = \"All changes saved\"\n }.bind(this), 200)\n }\n }.bind(this));\n }\n\n this.saveTitle = function($event) {\n $event.target.blur();\n this.saveNote($event);\n this.focusEditor();\n }\n\n var saveTimeout;\n this.changesMade = function() {\n this.note.hasChanges = true;\n this.note.dummy = false;\n apiController.saveDraftToDisk(this.note);\n\n if(saveTimeout) $timeout.cancel(saveTimeout);\n if(statusTimeout) $timeout.cancel(statusTimeout);\n saveTimeout = $timeout(function(){\n this.noteStatus = \"Saving...\";\n this.saveNote();\n }.bind(this), 150)\n }\n\n\n this.contentChanged = function() {\n this.changesMade();\n }\n\n this.nameChanged = function() {\n this.changesMade();\n }\n\n this.onNameFocus = function() {\n this.editingName = true;\n }\n\n this.onContentFocus = function() {\n this.showSampler = false;\n $rootScope.$broadcast(\"editorFocused\");\n this.editingUrl = false;\n }\n\n this.onNameBlur = function() {\n this.editingName = false;\n }\n\n this.toggleFullScreen = function() {\n this.fullscreen = !this.fullscreen;\n if(this.fullscreen) {\n if(this.editorMode == 'edit') {\n // refocus\n this.focusEditor(0);\n }\n } else {\n\n }\n }\n\n this.selectedMenuItem = function() {\n this.showMenu = false;\n }\n\n this.toggleMarkdown = function() {\n if(this.editorMode == 'preview') {\n this.editorMode = 'edit';\n } else {\n this.editorMode = 'preview';\n }\n }\n\n this.editUrlPressed = function() {\n this.showMenu = false;\n var url = this.publicUrlForNote(this.note);\n url = url.replace(this.note.presentation.root_path, \"\");\n this.url = {base: url, token : this.note.presentation.root_path};\n this.editingUrl = true;\n }\n\n this.saveUrl = function($event) {\n $event.target.blur();\n\n var original = this.note.presentation.relative_path;\n this.note.presentation.relative_path = this.url.token;\n\n apiController.updatePresentation(this.note, this.note.presentation, function(response){\n if(!response) {\n this.note.presentation.relative_path = original;\n this.url.token = original;\n alert(\"This URL is not available.\");\n } else {\n this.editingUrl = false;\n }\n }.bind(this))\n }\n\n this.shareNote = function() {\n\n function openInNewTab(url) {\n var a = document.createElement(\"a\");\n a.target = \"_blank\";\n a.href = url;\n a.click();\n }\n\n apiController.shareItem(this.user, this.note, function(note){\n openInNewTab(this.publicUrlForNote(note));\n }.bind(this))\n this.showMenu = false;\n }\n\n this.unshareNote = function() {\n apiController.unshareItem(this.user, this.note, function(note){\n\n })\n this.showMenu = false;\n }\n\n this.publicUrlForNote = function() {\n return this.note.presentationURL();\n }\n\n this.clickedMenu = function() {\n if(this.note.locked) {\n alert(\"This note has been shared without an account, and can therefore not be changed.\")\n } else {\n this.showMenu = !this.showMenu;\n }\n }\n\n this.deleteNote = function() {\n apiController.clearDraft();\n this.remove()(this.note);\n this.showMenu = false;\n }\n\n this.clickedEditNote = function() {\n this.editorMode = 'edit';\n this.focusEditor(100);\n }\n\n });\n;angular.module('app.frontend')\n .directive(\"groupsSection\", function(){\n return {\n restrict: 'E',\n scope: {\n addNew: \"&\",\n selectionMade: \"&\",\n willSelect: \"&\",\n save: \"&\",\n groups: \"=\",\n allGroup: \"=\",\n user: \"=\",\n updateNoteGroup: \"&\"\n },\n templateUrl: 'frontend/groups.html',\n replace: true,\n controller: 'GroupsCtrl',\n controllerAs: 'ctrl',\n bindToController: true,\n\n link:function(scope, elem, attrs, ctrl) {\n scope.$watch('ctrl.groups', function(newGroups){\n if(newGroups) {\n ctrl.setGroups(newGroups);\n }\n });\n }\n }\n })\n .controller('GroupsCtrl', function () {\n\n var initialLoad = true;\n\n this.setGroups = function(groups) {\n if(initialLoad) {\n initialLoad = false;\n this.selectGroup(this.allGroup);\n } else {\n if(groups && groups.length > 0) {\n this.selectGroup(groups[0]);\n }\n }\n }\n\n this.selectGroup = function(group) {\n this.willSelect()(group);\n this.selectedGroup = group;\n this.selectionMade()(group);\n }\n\n this.clickedAddNewGroup = function() {\n if(this.editingGroup) {\n return;\n }\n\n this.newGroup = new Group({notes : []});\n if(!this.user.uuid) {\n this.newGroup.uuid = Neeto.crypto.generateRandomKey()\n }\n this.selectedGroup = this.newGroup;\n this.editingGroup = this.newGroup;\n this.addNew()(this.newGroup);\n }\n\n var originalGroupName = \"\";\n this.onGroupTitleFocus = function(group) {\n originalGroupName = group.name;\n }\n\n this.groupTitleDidChange = function(group) {\n this.editingGroup = group;\n }\n\n this.saveGroup = function($event, group) {\n this.editingGroup = null;\n if(group.name.length == 0) {\n group.name = originalGroupName;\n originalGroupName = \"\";\n return;\n }\n\n $event.target.blur();\n if(!group.name || group.name.length == 0) {\n return;\n }\n\n this.save()(group, function(savedGroup){\n _.merge(group, savedGroup);\n this.selectGroup(group);\n this.newGroup = null;\n }.bind(this));\n }\n\n this.noteCount = function(group) {\n var validNotes = Note.filterDummyNotes(group.notes);\n return validNotes.length;\n }\n\n this.handleDrop = function(e, newGroup, note) {\n this.updateNoteGroup()(note, newGroup, this.selectedGroup);\n }.bind(this)\n\n\n });\n;angular.module('app.frontend')\n .directive(\"header\", function(){\n return {\n restrict: 'E',\n scope: {\n user: \"=\",\n logout: \"&\"\n },\n templateUrl: 'frontend/header.html',\n replace: true,\n controller: 'HeaderCtrl',\n controllerAs: 'ctrl',\n bindToController: true,\n\n link:function(scope, elem, attrs, ctrl) {\n\n }\n }\n })\n .controller('HeaderCtrl', function ($auth, $state, apiController, serverSideValidation, $timeout) {\n\n this.changePasswordPressed = function() {\n this.showNewPasswordForm = !this.showNewPasswordForm;\n }\n\n this.accountMenuPressed = function() {\n this.serverData = {url: apiController.getServer()};\n this.showAccountMenu = !this.showAccountMenu;\n this.showFaq = false;\n this.showNewPasswordForm = false;\n }\n\n this.changeServer = function() {\n apiController.setServer(this.serverData.url, true);\n }\n\n this.signOutPressed = function() {\n this.showAccountMenu = false;\n this.logout()();\n apiController.signout();\n window.location.reload();\n }\n\n this.submitPasswordChange = function() {\n this.passwordChangeData.status = \"Generating New Keys...\";\n\n $timeout(function(){\n if(data.password != data.password_confirmation) {\n alert(\"Your new password does not match its confirmation.\");\n return;\n }\n\n apiController.changePassword(this.user, this.passwordChangeData.current_password, this.passwordChangeData.new_password, function(response){\n\n })\n\n }.bind(this))\n }\n\n this.hasLocalData = function() {\n return this.user.filteredNotes().length > 0;\n }\n\n this.mergeLocalChanged = function() {\n if(!this.user.shouldMerge) {\n if(!confirm(\"Unchecking this option means any locally stored groups and notes you have now will be deleted. Are you sure you want to continue?\")) {\n this.user.shouldMerge = true;\n }\n }\n }\n\n this.loginSubmitPressed = function() {\n this.loginData.status = \"Generating Login Keys...\";\n $timeout(function(){\n apiController.login(this.loginData.email, this.loginData.user_password, function(response){\n if(response.errors) {\n this.loginData.status = response.errors[0];\n } else {\n this.onAuthSuccess(response.user);\n }\n }.bind(this));\n }.bind(this))\n }\n\n this.submitRegistrationForm = function() {\n this.loginData.status = \"Generating Account Keys...\";\n\n $timeout(function(){\n apiController.register(this.loginData.email, this.loginData.user_password, function(response){\n if(response.errors) {\n this.loginData.status = response.errors[0];\n } else {\n this.onAuthSuccess(response.user);\n }\n }.bind(this));\n }.bind(this))\n }\n\n this.forgotPasswordSubmit = function() {\n $auth.requestPasswordReset(this.resetData)\n .then(function(resp) {\n this.resetData.response = \"Success\";\n // handle success response\n }.bind(this))\n .catch(function(resp) {\n // handle error response\n this.resetData.response = \"Error\";\n }.bind(this));\n }\n\n this.encryptionStatusForNotes = function() {\n var allNotes = this.user.filteredNotes();\n var countEncrypted = 0;\n allNotes.forEach(function(note){\n if(note.encryptionEnabled()) {\n countEncrypted++;\n }\n }.bind(this))\n\n return countEncrypted + \"/\" + allNotes.length + \" notes encrypted\";\n }\n\n this.downloadDataArchive = function() {\n var link = document.createElement('a');\n link.setAttribute('download', 'neeto.json');\n link.href = apiController.notesDataFile(this.user);\n link.click();\n }\n\n this.importFileSelected = function(files) {\n var file = files[0];\n var reader = new FileReader();\n reader.onload = function(e) {\n apiController.importJSONData(e.target.result, function(success, response){\n console.log(\"import response\", success, response);\n if(success) {\n // window.location.reload();\n } else {\n alert(\"There was an error importing your data. Please try again.\");\n }\n })\n }\n reader.readAsText(file);\n }\n\n this.onAuthSuccess = function(user) {\n this.user.id = user.id;\n\n if(this.user.shouldMerge && this.hasLocalData()) {\n apiController.mergeLocalDataRemotely(this.user, function(){\n window.location.reload();\n });\n } else {\n window.location.reload();\n }\n\n this.showLogin = false;\n this.showRegistration = false;\n }\n\n });\n;angular.module('app.frontend')\n.controller('HomeCtrl', function ($scope, $rootScope, $timeout, apiController, modelManager) {\n $rootScope.bodyClass = \"app-body-class\";\n $rootScope.title = \"Notes — Neeto, a secure code box for developers\";\n $rootScope.description = \"A secure code box for developers to store common commands and useful notes.\";\n\n var onUserSet = function() {\n\n $scope.allGroup = new Group({name: \"All\", all: true});\n $scope.groups = modelManager.groups;\n\n apiController.verifyEncryptionStatusOfAllItems($scope.defaultUser, function(success){\n\n });\n }\n\n apiController.getCurrentUser(function(response){\n if(response && !response.errors) {\n $scope.defaultUser = new User(response);\n modelManager.items = response.items;\n $rootScope.title = \"Notes — Neeto\";\n onUserSet();\n } else {\n $scope.defaultUser = new User(apiController.localUser());\n onUserSet();\n }\n });\n\n /*\n Groups Ctrl Callbacks\n */\n\n $scope.updateAllGroup = function() {\n $scope.allGroup.notes = modelManager.filteredNotes;\n }\n\n $scope.groupsWillMakeSelection = function(group) {\n if(group.all) {\n $scope.updateAllGroup();\n }\n }\n\n $scope.groupsSelectionMade = function(group) {\n if(!group.notes) {\n group.notes = [];\n }\n $scope.selectedGroup = group;\n }\n\n $scope.groupsAddNew = function(group) {\n modelManager.addTag(group);\n }\n\n $scope.groupsSave = function(group, callback) {\n apiController.saveItems([group], callback);\n }\n\n /*\n Called to update the group of a note after drag and drop change\n The note object is a copy of the original\n */\n $scope.groupsUpdateNoteGroup = function(noteCopy, newGroup, oldGroup) {\n\n var originalNote = _.find($scope.defaultUser.notes, {uuid: noteCopy.uuid});\n modelManager.removeTagFromNote(oldGroup, originalNote);\n if(!newGroup.all) {\n modelManager.addTagToNote(newGroup, originalNote);\n }\n\n apiController.saveDirtyItems(function(){});\n }\n\n /*\n Notes Ctrl Callbacks\n */\n\n $scope.notesRemoveGroup = function(group) {\n var validNotes = Note.filterDummyNotes(group.notes);\n if(validNotes == 0) {\n // if no more notes, delete group\n apiController.deleteItem($scope.defaultUser, group, function(){\n // force scope groups to update on sub directives\n $scope.groups = [];\n $timeout(function(){\n $scope.groups = modelManager.groups;\n })\n });\n } else {\n alert(\"To delete this group, remove all its notes first.\");\n }\n }\n\n $scope.notesSelectionMade = function(note) {\n $scope.selectedNote = note;\n }\n\n $scope.notesAddNew = function(note) {\n if(!$scope.defaultUser.id) {\n // generate local id for note\n note.id = Neeto.crypto.generateRandomKey();\n }\n\n modelManager.addNote(note);\n\n if(!$scope.selectedGroup.all) {\n modelManager.addTagToNote($scope.selectedGroup, note);\n }\n }\n\n /*\n Shared Callbacks\n */\n\n $scope.saveNote = function(note, callback) {\n apiController.saveItems([note], function(){\n modelManager.addNote(note);\n note.hasChanges = false;\n\n if(callback) {\n callback(true);\n }\n })\n }\n\n $scope.deleteNote = function(note) {\n\n modelManager.deleteNote(note);\n\n if(note == $scope.selectedNote) {\n $scope.selectedNote = null;\n }\n\n if(note.dummy) {\n return;\n }\n\n apiController.deleteItem($scope.defaultUser, note, function(success){})\n apiController.saveDirtyItems(function(){});\n }\n\n /*\n Header Ctrl Callbacks\n */\n\n $scope.headerLogout = function() {\n $scope.defaultUser = apiController.localUser();\n $scope.groups = $scope.defaultUser.groups;\n }\n\n\n});\n;angular.module('app.frontend')\n .directive(\"notesSection\", function(){\n return {\n scope: {\n addNew: \"&\",\n selectionMade: \"&\",\n remove: \"&\",\n group: \"=\",\n user: \"=\",\n removeGroup: \"&\"\n },\n templateUrl: 'frontend/notes.html',\n replace: true,\n controller: 'NotesCtrl',\n controllerAs: 'ctrl',\n bindToController: true,\n\n link:function(scope, elem, attrs, ctrl) {\n scope.$watch('ctrl.group', function(group, oldGroup){\n if(group) {\n ctrl.groupDidChange(group, oldGroup);\n }\n });\n }\n }\n })\n .controller('NotesCtrl', function (apiController, $timeout, ngDialog, $rootScope) {\n\n $rootScope.$on(\"editorFocused\", function(){\n this.showMenu = false;\n }.bind(this))\n\n var isFirstLoad = true;\n\n this.groupDidChange = function(group, oldGroup) {\n this.showMenu = false;\n\n if(this.selectedNote && this.selectedNote.dummy) {\n _.remove(oldGroup.notes, this.selectedNote);\n }\n\n this.noteFilter.text = \"\";\n this.setNotes(group.notes, false);\n\n if(isFirstLoad) {\n $timeout(function(){\n var draft = apiController.getDraft();\n if(draft) {\n var note = draft;\n this.selectNote(note);\n } else {\n this.createNewNote();\n isFirstLoad = false;\n }\n }.bind(this))\n } else if(group.notes.length == 0) {\n this.createNewNote();\n }\n }\n\n this.selectedGroupDelete = function() {\n this.showMenu = false;\n this.removeGroup()(this.group);\n }\n\n this.selectedGroupShare = function() {\n this.showMenu = false;\n\n if(!this.user.id) {\n alert(\"You must be signed in to share a group.\");\n return;\n }\n\n if(this.group.all) {\n alert(\"You cannot share the 'All' group.\");\n return;\n }\n\n var callback = function(username) {\n apiController.shareItem(this.user, this.group, function(response){\n })\n }.bind(this);\n\n if(!this.user.username) {\n ngDialog.open({\n template: 'frontend/modals/username.html',\n controller: 'UsernameModalCtrl',\n resolve: {\n user: function() {return this.user}.bind(this),\n callback: function() {return callback}\n },\n className: 'ngdialog-theme-default',\n disableAnimation: true\n });\n } else {\n callback(this.user.username);\n }\n }\n\n this.selectedGroupUnshare = function() {\n this.showMenu = false;\n apiController.unshareItem(this.user, this.group, function(response){\n\n })\n }\n\n this.publicUrlForGroup = function() {\n return this.group.presentation.url;\n }\n\n this.setNotes = function(notes, createNew) {\n this.notes = notes;\n notes.forEach(function(note){\n note.visible = true;\n })\n apiController.decryptNotesWithLocalKey(notes);\n this.selectFirstNote(createNew);\n }\n\n this.selectFirstNote = function(createNew) {\n var visibleNotes = this.notes.filter(function(note){\n return note.visible;\n });\n\n if(visibleNotes.length > 0) {\n this.selectNote(visibleNotes[0]);\n } else if(createNew) {\n this.createNewNote();\n }\n }\n\n this.selectNote = function(note) {\n this.selectedNote = note;\n this.selectionMade()(note);\n }\n\n this.createNewNote = function() {\n var title = \"New Note\" + (this.notes ? (\" \" + (this.notes.length + 1)) : \"\");\n this.newNote = new Note({dummy: true});\n this.newNote.content.title = title;\n modelManager.addTagToNote(this.group, this.newNote);\n this.selectNote(this.newNote);\n this.addNew()(this.newNote);\n }\n\n this.noteFilter = {text : ''};\n\n this.filterNotes = function(note) {\n if(this.noteFilter.text.length == 0) {\n note.visible = true;\n } else {\n note.visible = note.title.toLowerCase().includes(this.noteFilter.text) || note.text.toLowerCase().includes(this.noteFilter.text);\n }\n return note.visible;\n }.bind(this)\n\n this.filterTextChanged = function() {\n $timeout(function(){\n if(!this.selectedNote.visible) {\n this.selectFirstNote(false);\n }\n }.bind(this), 100)\n }\n });\n;angular.module('app.frontend')\n.controller('UsernameModalCtrl', function ($scope, apiController, Restangular, user, callback, $timeout) {\n $scope.formData = {};\n\n $scope.saveUsername = function() {\n apiController.setUsername(user, $scope.formData.username, function(response){\n var username = response.root_path;\n user.presentation = response;\n callback(username);\n $scope.closeThisDialog();\n })\n }\n});\n;class Item {\n\n constructor(json_obj) {\n var content;\n\n Object.defineProperty(this, \"content\", {\n get: function() {\n return content;\n },\n set: function(value) {\n var finalValue = value;\n\n if(typeof value === 'string') {\n try {\n decodedValue = JSON.parse(value);\n finalValue = decodedValue;\n }\n catch(e) {\n finalValue = value;\n }\n }\n\n content = finalValue;\n },\n enumerable: true,\n });\n\n _.merge(this, json_obj);\n\n this.setContentRaw = function(rawContent) {\n content = rawContent;\n }\n }\n\n referencesMatchingContentType(contentType) {\n return this.references.filter(function(reference){\n return reference.content_type == content_type;\n });\n }\n\n updateReferencesLocalMapping() {\n // should be overriden to manage local properties\n }\n\n /* Returns true if note is shared individually or via group */\n isPublic() {\n return this.presentation;\n }\n\n isEncrypted() {\n return this.encryptionEnabled() && typeof this.content === 'string' ? true : false;\n }\n\n encryptionEnabled() {\n return this.loc_eek;\n }\n\n presentationURL() {\n return this.presentation.url;\n }\n}\n;class Note extends Item {\n\n constructor(json_obj) {\n\n super(json_obj);\n\n if(!this.content) {\n this.content = {title: \"\", text: \"\"};\n }\n }\n\n filterDummyNotes(notes) {\n var filtered = notes.filter(function(note){return note.dummy == false || note.dummy == null});\n return filtered;\n }\n\n get hasOnePublicGroup() {\n var hasPublicGroup = false;\n this.groups.forEach(function(group){\n if(group.isPublic()) {\n hasPublicGroup = true;\n return;\n }\n })\n\n return hasPublicGroup;\n }\n\n isPublic() {\n return super.isPublic() || this.hasOnePublicGroup;\n }\n\n get content_type() {\n return \"Note\";\n }\n}\n;class Tag extends Item {\n\n constructor(json_obj) {\n super(json_obj);\n }\n\n get content_type() {\n return \"Tag\";\n }\n}\n;class User {\n constructor(json_obj) {\n _.merge(this, json_obj);\n }\n}\n;angular.module('app.frontend')\n .provider('apiController', function () {\n\n function domainName() {\n var domain_comps = location.hostname.split(\".\");\n var domain = domain_comps[domain_comps.length - 2] + \".\" + domain_comps[domain_comps.length - 1];\n return domain;\n }\n\n var url;\n\n this.defaultServerURL = function() {\n if(!url) {\n url = localStorage.getItem(\"server\");\n if(!url) {\n url = location.protocol + \"//\" + domainName() + (location.port ? ':' + location.port: '');\n }\n }\n return url;\n }\n\n\n this.$get = function(Restangular) {\n return new ApiController(Restangular);\n }\n\n function ApiController(Restangular) {\n\n /*\n Config\n */\n\n this.getServer = function() {\n if(!url) {\n url = localStorage.getItem(\"server\");\n if(!url) {\n url = location.protocol + \"//\" + domainName() + (location.port ? ':' + location.port: '');\n this.setServer(url);\n }\n }\n return url;\n }\n\n this.setServer = function(url, refresh) {\n localStorage.setItem(\"server\", url);\n if(refresh) {\n window.location.reload();\n }\n }\n\n\n /*\n Auth\n */\n\n this.getCurrentUser = function(callback) {\n if(!localStorage.getItem(\"jwt\")) {\n callback(null);\n return;\n }\n Restangular.one(\"users/current\").get().then(function(response){\n callback(response.plain());\n })\n }\n\n this.login = function(email, password, callback) {\n var keys = Neeto.crypto.generateEncryptionKeysForUser(password, email);\n this.setGk(keys.gk);\n var request = Restangular.one(\"auth/sign_in.json\");\n request.user = {password: keys.pw, email: email};\n request.post().then(function(response){\n localStorage.setItem(\"jwt\", response.token);\n callback(response);\n })\n }\n\n this.register = function(email, password, callback) {\n var keys = Neeto.crypto.generateEncryptionKeysForUser(password, email);\n this.setGk(keys.gk);\n var request = Restangular.one(\"auth.json\");\n request.user = {password: keys.pw, email: email};\n request.post().then(function(response){\n localStorage.setItem(\"jwt\", response.token);\n callback(response);\n })\n }\n\n this.changePassword = function(user, current_password, new_password) {\n var current_keys = Neeto.crypto.generateEncryptionKeysForUser(current_password, user.email);\n var new_keys = Neeto.crypto.generateEncryptionKeysForUser(new_password, user.email);\n\n var data = {};\n data.current_password = current_keys.pw;\n data.password = new_keys.pw;\n data.password_confirmation = new_keys.pw;\n\n var user = this.user;\n\n this._performPasswordChange(current_keys, new_keys, function(response){\n if(response && !response.errors) {\n // this.showNewPasswordForm = false;\n // reencrypt data with new gk\n this.reencryptAllNotesAndSave(user, new_keys.gk, current_keys.gk, function(success){\n if(success) {\n this.setGk(new_keys.gk);\n alert(\"Your password has been changed and your data re-encrypted.\");\n } else {\n // rollback password\n this._performPasswordChange(new_keys, current_keys, function(response){\n alert(\"There was an error changing your password. Your password has been rolled back.\");\n window.location.reload();\n })\n }\n }.bind(this));\n } else {\n // this.showNewPasswordForm = false;\n alert(\"There was an error changing your password. Please try again.\");\n }\n })\n }\n\n this._performPasswordChange = function(email, current_keys, new_keys, callback) {\n var request = Restangular.one(\"auth\");\n request.user = {password: new_keys.pw, password_confirmation: new_keys.pw, current_password: current_keys.pw, email: email};\n request.patch().then(function(response){\n callback(response);\n })\n }\n\n\n /*\n User\n */\n\n this.setUsername = function(user, username, callback) {\n var request = Restangular.one(\"users\", user.id).one(\"set_username\");\n request.username = username;\n request.post().then(function(response){\n callback(response.plain());\n })\n }\n\n /*\n Ensures that if encryption is disabled, all local notes are uncrypted,\n and that if it's enabled, that all local notes are encrypted\n */\n this.verifyEncryptionStatusOfAllItems = function(user, callback) {\n var allNotes = user.filteredNotes();\n var notesNeedingUpdate = [];\n allNotes.forEach(function(note){\n if(!note.isPublic()) {\n if(note.encryptionEnabled() && !note.isEncrypted()) {\n notesNeedingUpdate.push(note);\n }\n } else {\n if(note.isEncrypted()) {\n notesNeedingUpdate.push(note);\n }\n }\n }.bind(this))\n\n if(notesNeedingUpdate.length > 0) {\n console.log(\"verifying encryption, notes need updating\", notesNeedingUpdate);\n this.saveBatchNotes(user, notesNeedingUpdate, callback)\n }\n }\n\n\n\n /*\n Items\n */\n\n this.saveDirtyItems = function(callback) {\n var dirtyItems = modelManager.dirtyItems;\n\n this.saveItems(dirtyItems, function(response){\n modelManager.clearDirtyItems();\n })\n }\n\n this.saveItems = function(items, callback) {\n var request = Restangular.one(\"users\", user.uuid).one(\"items\");\n request.items = _.map(items, function(item){\n return this.createRequestParamsFromItem(item, user);\n }.bind(this));\n\n request.post().then(function(response) {\n var savedItems = response.items;\n items.forEach(function(item){\n _.merge(item, _.find(savedItems, {uuid: item.uuid}));\n })\n callback(response);\n })\n }\n\n this.createRequestParamsForItem = function(item, user) {\n var params = {uuid: item.uuid};\n\n if(!item.isPublic()) {\n // encrypted\n var itemCopy = _.cloneDeep(item);\n this.encryptSingleNote(itemCopy, this.retrieveGk());\n params.content = itemCopy.content;\n params.loc_eek = itemCopy.loc_eek;\n }\n else {\n // decrypted\n params.content = JSON.stringify(item.content);\n params.loc_eek = null;\n }\n return params;\n }\n\n\n this.deleteItem = function(user, item, callback) {\n if(!user.id) {\n this.writeUserToLocalStorage(user);\n callback(true);\n } else {\n Restangular.one(\"users\", user.uuid).one(\"items\", item.uuid).remove()\n .then(function(response) {\n callback(true);\n })\n }\n }\n\n this.shareItem = function(user, item, callback) {\n if(!user.id) {\n alert(\"You must be signed in to share.\");\n } else {\n Restangular.one(\"users\", user.uuid).one(\"items\", item.uuid).one(\"presentations\").post()\n .then(function(response){\n var presentation = response.plain();\n _.merge(item, {presentation: presentation});\n callback(item);\n\n // decrypt references\n if(item.references.length > 0) {\n this.saveBatchItems(user, item.references, function(success){})\n }\n })\n }\n }\n\n this.unshareItem = function(user, item, callback) {\n var request = Restangular.one(\"users\", user.uuid).one(\"notes\", item.uuid).one(\"presentations\", item.presentation.uuid);\n request.remove().then(function(response){\n item.presentation = null;\n callback(null);\n\n // encrypt references\n if(item.references.length > 0) {\n this.saveBatchItems(user, item.references, function(success){})\n }\n })\n }\n\n\n /*\n Presentations\n */\n\n this.updatePresentation = function(resource, presentation, callback) {\n var request = Restangular.one(\"users\", user.id)\n .one(\"items\", resource.id)\n .one(\"presentations\", resource.presentation.id);\n _.merge(request, presentation);\n request.patch().then(function(response){\n callback(response.plain());\n })\n .catch(function(error){\n callback(nil);\n })\n }\n\n\n /*\n Import\n */\n\n this.importJSONData = function(jsonString, callback) {\n var data = JSON.parse(jsonString);\n var user = new User(data);\n console.log(\"importing data\", JSON.parse(jsonString));\n user.notes.forEach(function(note) {\n if(note.isPublic()) {\n note.setContentRaw(JSON.stringify(note.content));\n } else {\n this.encryptSingleNoteWithLocalKey(note);\n }\n\n // prevent circular links\n note.group = null;\n }.bind(this))\n\n user.groups.forEach(function(group){\n // prevent circular links\n group.notes = null;\n })\n\n var request = Restangular.one(\"import\");\n request.data = {notes: user.notes, groups: user.groups};\n request.post().then(function(response){\n callback(true, response);\n })\n .catch(function(error){\n callback(false, error);\n })\n }\n\n /*\n Export\n */\n\n this.notesDataFile = function(user) {\n var textFile = null;\n var makeTextFile = function (text) {\n var data = new Blob([text], {type: 'text/json'});\n\n // If we are replacing a previously generated file we need to\n // manually revoke the object URL to avoid memory leaks.\n if (textFile !== null) {\n window.URL.revokeObjectURL(textFile);\n }\n\n textFile = window.URL.createObjectURL(data);\n\n // returns a URL you can use as a href\n return textFile;\n }.bind(this);\n\n var presentationParams = function(presentation) {\n if(!presentation) {\n return null;\n }\n\n return {\n id: presentation.id,\n uuid: presentation.uuid,\n root_path: presentation.root_path,\n relative_path: presentation.relative_path,\n presentable_type: presentation.presentable_type,\n presentable_id: presentation.presentable_id,\n created_at: presentation.created_at,\n modified_at: presentation.modified_at,\n }\n }\n\n var notes = _.map(user.filteredNotes(), function(note){\n return {\n id: note.id,\n uuid: note.uuid,\n content: note.content,\n group_id: note.group_id,\n created_at: note.created_at,\n modified_at: note.modified_at,\n presentation: presentationParams(note.presentation)\n }\n });\n\n var groups = _.map(user.groups, function(group){\n return {\n id: group.id,\n uuid: group.uuid,\n name: group.name,\n created_at: group.created_at,\n modified_at: group.modified_at,\n presentation: presentationParams(group.presentation)\n }\n });\n\n var data = {\n notes: notes,\n groups: groups\n }\n\n return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */));\n }\n\n\n\n\n /*\n Merging\n */\n this.mergeLocalDataRemotely = function(user, callback) {\n var request = Restangular.one(\"users\", user.id).one(\"merge\");\n var groups = user.groups;\n request.notes = user.notes;\n request.notes.forEach(function(note){\n if(note.group_id) {\n var group = groups.filter(function(group){return group.id == note.group_id})[0];\n note.group_name = group.name;\n }\n })\n request.post().then(function(response){\n callback();\n localStorage.removeItem('user');\n })\n }\n\n\n\n\n\n\n this.staticifyObject = function(object) {\n return JSON.parse(JSON.stringify(object));\n }\n\n this.writeUserToLocalStorage = function(user) {\n var saveUser = _.cloneDeep(user);\n saveUser.notes = Note.filterDummyNotes(saveUser.notes);\n saveUser.groups.forEach(function(group){\n group.notes = null;\n }.bind(this))\n this.writeToLocalStorage('user', saveUser);\n }\n\n this.writeToLocalStorage = function(key, value) {\n localStorage.setItem(key, angular.toJson(value));\n }\n\n this.localUser = function() {\n var user = JSON.parse(localStorage.getItem('user'));\n if(!user) {\n user = {notes: [], groups: []};\n }\n user.shouldMerge = true;\n return user;\n }\n\n /*\n Drafts\n */\n\n this.saveDraftToDisk = function(draft) {\n localStorage.setItem(\"draft\", JSON.stringify(draft));\n }\n\n this.clearDraft = function() {\n localStorage.removeItem(\"draft\");\n }\n\n this.getDraft = function() {\n var draftString = localStorage.getItem(\"draft\");\n if(!draftString || draftString == 'undefined') {\n return null;\n }\n return new Note(JSON.parse(draftString));\n }\n\n\n /*\n Encrpytion\n */\n\n this.retrieveGk = function() {\n if(!this.gk) {\n this.gk = localStorage.getItem(\"gk\");\n }\n return this.gk;\n }\n\n this.setGk = function(gk) {\n localStorage.setItem('gk', gk);\n }\n\n this.signout = function() {\n localStorage.removeItem(\"jwt\");\n localStorage.removeItem(\"gk\");\n }\n\n this.encryptSingleNote = function(note, key) {\n var ek = null;\n if(note.loc_eek) {\n ek = Neeto.crypto.decryptText(note.loc_eek, key);\n } else {\n ek = Neeto.crypto.generateRandomEncryptionKey();\n note.loc_eek = Neeto.crypto.encryptText(ek, key);\n }\n note.content = Neeto.crypto.encryptText(JSON.stringify(note.content), ek);\n note.local_encryption_scheme = \"1.0\";\n }\n\n this.encryptNotes = function(notes, key) {\n notes.forEach(function(note){\n this.encryptSingleNote(note, key);\n }.bind(this));\n }\n\n this.encryptSingleNoteWithLocalKey = function(note) {\n this.encryptSingleNote(note, this.retrieveGk());\n }\n\n this.encryptNotesWithLocalKey = function(notes) {\n this.encryptNotes(notes, this.retrieveGk());\n }\n\n this.encryptNonPublicNotesWithLocalKey = function(notes) {\n var nonpublic = notes.filter(function(note){\n return !note.isPublic() && !note.pending_share;\n })\n this.encryptNotes(nonpublic, this.retrieveGk());\n }\n\n this.decryptSingleNoteWithLocalKey = function(note) {\n this.decryptSingleNote(note, this.retrieveGk());\n }\n\n this.decryptSingleNote = function(note, key) {\n var ek = Neeto.crypto.decryptText(note.loc_eek || note.local_eek, key);\n var content = Neeto.crypto.decryptText(note.content, ek);\n // console.log(\"decrypted contnet\", content);\n note.content = content;\n }\n\n this.decryptNotes = function(notes, key) {\n notes.forEach(function(note){\n // console.log(\"is encrypted?\", note);\n if(note.isEncrypted()) {\n this.decryptSingleNote(note, key);\n }\n }.bind(this));\n }\n\n this.decryptNotesWithLocalKey = function(notes) {\n this.decryptNotes(notes, this.retrieveGk());\n }\n\n this.reencryptAllNotesAndSave = function(user, newKey, oldKey, callback) {\n var notes = user.filteredNotes();\n notes.forEach(function(note){\n if(note.isEncrypted()) {\n // first decrypt eek with old key\n var ek = Neeto.crypto.decryptText(note.loc_eek, oldKey);\n // now encrypt ek with new key\n note.loc_eek = Neeto.crypto.encryptText(ek, newKey);\n }\n });\n\n this.saveBatchNotes(user, notes, function(success) {\n callback(success);\n }.bind(this));\n }\n }\n});\n;\nclass ItemManager {\n\n constructor() {\n\n }\n\n set items(items) {\n this.items = items;\n resolveReferences();\n }\n\n referencesForItemId(itemId) {\n return _.find(this.items, {uuid: itemId});\n }\n\n resolveReferences() {\n this.items.forEach(function(item){\n // build out references\n _.map(item.references, function(reference){\n return referencesForItemId(reference.uuid);\n })\n });\n }\n\n itemsForContentType(contentType) {\n this.items.filter(function(item){\n return item.content_type == contentType;\n });\n }\n\n // returns dirty item references that need saving\n deleteItem(item) {\n _.remove(this.items, item);\n item.references.forEach(function(referencedItem){\n removeReferencesBetweenItems(referencedItem, item);\n })\n\n return item.references;\n }\n\n removeReferencesBetweenItems(itemOne, itemTwo) {\n _.remove(itemOne.references, _.find(itemOne.references, {uuid: itemTwo.uuid}));\n _.remove(itemTwo.references, _.find(itemTwo.references, {uuid: itemOne.uuid}));\n return [itemOne, itemTwo];\n }\n\n createReferencesBetweenItems(itemOne, itemTwo) {\n itemOne.references.push(itemTwo);\n itemTwo.references.push(itemOne);\n return [itemOne, itemTwo];\n }\n}\n\nangular.module('app.frontend').service('itemManager', ItemManager);\n;angular.module('app.frontend')\n .service('markdownRenderer', function ($sce) {\n\n marked.setOptions({\n breaks: true,\n sanitize: true\n });\n\n this.renderedContentForText = function(text) {\n if(!text || text.length == 0) {\n return \"\";\n }\n return marked(text);\n }\n\n this.renderHtml = function(html_code) {\n return $sce.trustAsHtml(html_code);\n };\n\n\n });\n;class ModelManager extends ItemManager {\n\n set items(items) {\n super.items = items;\n\n this.notes = _.map(this.items.itemsForContentType(\"Note\"), function(json_obj) {\n return new Note(json_obj);\n })\n\n this.groups = _.map(this.items.itemsForContentType(\"Group\"), function(json_obj) {\n var group = Group(json_obj);\n group.updateReferencesLocalMapping();\n return group;\n })\n }\n\n addDirtyItems(items) {\n if(this.dirtyItems) {\n this.dirtyItems = [];\n }\n\n this.dirtyItems.concat(items);\n }\n\n get dirtyItems() {\n return this.dirtyItems || [];\n }\n\n get filteredNotes() {\n return Note.filterDummyNotes(this.notes);\n }\n\n clearDirtyItems() {\n this.dirtyItems = [];\n }\n\n addNote(note) {\n if(!_.find(this.notes, {uuid: note.uuid})) {\n this.notes.unshift(note);\n }\n }\n\n addTag(tag) {\n this.tags.unshift(tag);\n }\n\n addTagToNote(tag, note) {\n var dirty = this.createReferencesBetweenItems(tag, note);\n this.refreshRelationshipsForTag(tag);\n this.refreshRelationshipsForNote(note);\n this.addDirtyItems(dirty);\n }\n\n refreshRelationshipsForTag(tag) {\n tag.notes = tag.referencesMatchingContentType(\"Note\");\n tag.notes.sort(function(a,b){\n return new Date(b.created_at) - new Date(a.created_at);\n });\n }\n\n refreshRelationshipsForNote(note) {\n note.groups = note.referencesMatchingContentType(\"Group\");\n }\n\n removeTagFromNote(tag, note) {\n var dirty = this.removeReferencesBetweenItems(tag, note);\n this.addDirtyItems(dirty);\n }\n\n deleteNote(note) {\n var dirty = this.deleteItem(note);\n this.addDirtyItems(dirty);\n }\n\n deleteTag(tag) {\n var dirty = this.deleteItem(tag);\n this.addDirtyItems(dirty);\n }\n\n filteredNotes() {\n return Note.filterDummyNotes(this.notes);\n }\n}\n\nangular.module('app.frontend').service('modelManager', ModelManager);\n;angular.module('app.frontend')\n .service('serverSideValidation', function ($sce) {\n // Show validation errors in form.\n this.showErrors = function (formErrors, form) {\n angular.forEach(formErrors, function (errors, key) {\n if (typeof form[key] !== 'undefined') {\n form[key].$setDirty();\n form[key].$setValidity('server', false);\n form[key].$error.server = $sce.trustAsHtml(errors.join(', '));\n }\n });\n };\n\n // Get validation errors from server response and show them in form.\n this.parseErrors = function (response, form) {\n if (response.status === 422) {\n this.showErrors(response.data, form);\n }\n };\n});\n;angular\n .module('app.frontend')\n .directive('mbAutofocus', ['$timeout', function($timeout) {\n return {\n restrict: 'A',\n scope: {\n shouldFocus: \"=\"\n },\n link : function($scope, $element) {\n $timeout(function() {\n if($scope.shouldFocus) {\n $element[0].focus();\n }\n });\n }\n }\n }]);\n;angular\n .module('app.frontend')\n .directive('draggable', function() {\n return {\n scope: {\n note: \"=\"\n },\n link: function(scope, element) {\n // this gives us the native JS object\n var el = element[0];\n\n el.draggable = true;\n\n el.addEventListener(\n 'dragstart',\n function(e) {\n e.dataTransfer.effectAllowed = 'move';\n e.dataTransfer.setData('Note', JSON.stringify(scope.note));\n this.classList.add('drag');\n return false;\n },\n false\n );\n\n el.addEventListener(\n 'dragend',\n function(e) {\n this.classList.remove('drag');\n return false;\n },\n false\n );\n }\n }\n});\n\nangular\n .module('app.frontend')\n .directive('droppable', function() {\n return {\n scope: {\n drop: '&',\n bin: '=',\n group: \"=\"\n },\n link: function(scope, element) {\n // again we need the native object\n var el = element[0];\n\n el.addEventListener(\n 'dragover',\n function(e) {\n e.dataTransfer.dropEffect = 'move';\n // allows us to drop\n if (e.preventDefault) e.preventDefault();\n this.classList.add('over');\n return false;\n },\n false\n );\n\n var counter = 0;\n\n el.addEventListener(\n 'dragenter',\n function(e) {\n counter++;\n this.classList.add('over');\n return false;\n },\n false\n );\n\n el.addEventListener(\n 'dragleave',\n function(e) {\n counter--;\n if (counter === 0) {\n this.classList.remove('over');\n }\n return false;\n },\n false\n );\n\n el.addEventListener(\n 'drop',\n function(e) {\n // Stops some browsers from redirecting.\n if (e.stopPropagation) e.stopPropagation();\n\n this.classList.remove('over');\n\n var binId = this.id;\n var note = new Note(JSON.parse(e.dataTransfer.getData('Note')));\n scope.$apply(function(scope) {\n var fn = scope.drop();\n if ('undefined' !== typeof fn) {\n fn(e, scope.group, note);\n }\n });\n\n return false;\n },\n false\n );\n }\n }\n});\n;angular\n .module('app.frontend')\n .directive('fileChange', function() {\n return {\n restrict: 'A',\n scope: {\n handler: '&'\n },\n link: function (scope, element) {\n element.on('change', function (event) {\n scope.$apply(function(){\n scope.handler({files: event.target.files});\n });\n });\n }\n };\n});\n;angular\n .module('app.frontend')\n .directive('lowercase', function() {\n return {\n require: 'ngModel',\n link: function(scope, element, attrs, modelCtrl) {\n var lowercase = function(inputValue) {\n if (inputValue == undefined) inputValue = '';\n var lowercased = inputValue.toLowerCase();\n if (lowercased !== inputValue) {\n modelCtrl.$setViewValue(lowercased);\n modelCtrl.$render();\n }\n return lowercased;\n }\n modelCtrl.$parsers.push(lowercase);\n lowercase(scope[attrs.ngModel]);\n }\n };\n });\n;angular\n .module('app.frontend')\n .directive('selectOnClick', ['$window', function ($window) {\n return {\n restrict: 'A',\n link: function (scope, element, attrs) {\n element.on('focus', function () {\n if (!$window.getSelection().toString()) {\n // Required for mobile Safari\n this.setSelectionRange(0, this.value.length)\n }\n });\n }\n };\n}]);\n;angular\n .module('app.frontend')\n .directive('note', function($timeout) {\n return {\n restrict: 'E',\n controller: 'SingleNoteCtrl',\n templateUrl: \"frontend/directives/note.html\",\n scope: {\n note: \"=\"\n },\n }\n })\n .controller('SingleNoteCtrl', function ($rootScope, $scope, $state, markdownRenderer) {\n $scope.renderedContent = function() {\n return markdownRenderer.renderHtml(markdownRenderer.renderedContentForText($scope.note.text));\n }\n });\n;/**\n * AngularJS directive that simulates the effect of typing on a text editor - with a blinking cursor.\n * This directive works as an attribute to any HTML element, and it changes the speed/delay of its animation.\n *\n * There's also a simple less file included for basic styling of the dialog, which can be overridden.\n * The config object also lets the user define custom CSS classes for the modal.\n *\n * How to use:\n *\n * Just add the desired text to the 'text' attribute of the element and the directive takes care of the rest.\n * The 'text' attribute can be a single string or an array of string. In case an array is passed, the string\n * on each index is erased so the next item can be printed. When the last index is reached, that string stays\n * on the screen. (So if you want to erase the last string, just push an empty string to the end of the array)\n *\n * These are the optional preferences:\n * - initial delay: set an 'initial-delay' attribute for the element\n * - type delay: set a 'type-delay' attribute for the element\n * - erase delay: set a 'erase-delay' attribute for the element\n * - specify cursor : set a 'cursor' attribute for the element, specifying which cursor to use\n * - turn off cursor blinking: set the 'blink-cursor' attribute to \"false\"\n * - cursor blinking speed: set a 'blink-delay' attribute for the element\n * - scope callback: pass the desired scope callback as the 'callback-fn' attribute of the element\n *\n * Note:\n * Each time/delay value should be set either on seconds (1s) or milliseconds (1000)\n *\n * Dependencies:\n * The directive needs the css file provided in order to replicate the cursor blinking effect.\n */\n\n\nangular\n .module('app.frontend').directive('typewrite', ['$timeout', function ($timeout) {\n function linkFunction($scope, $element, $attrs) {\n var timer = null,\n initialDelay = $attrs.initialDelay ? getTypeDelay($attrs.initialDelay) : 200,\n typeDelay = $attrs.typeDelay || 200,\n eraseDelay = $attrs.eraseDelay || typeDelay / 2,\n blinkDelay = $attrs.blinkDelay ? getAnimationDelay($attrs.blinkDelay) : false,\n cursor = $attrs.cursor || '|',\n blinkCursor = typeof $attrs.blinkCursor !== 'undefined' ? $attrs.blinkCursor === 'true' : true,\n currentText,\n textArray,\n running,\n auxStyle;\n\n\n\n if ($scope.text) {\n if ($scope.text instanceof Array) {\n textArray = $scope.text;\n currentText = textArray[0];\n } else {\n currentText = $scope.text;\n }\n }\n if (typeof $scope.start === 'undefined' || $scope.start) {\n typewrite();\n }\n\n function typewrite() {\n timer = $timeout(function () {\n updateIt($element, 0, 0, currentText);\n }, initialDelay);\n }\n\n function updateIt(element, charIndex, arrIndex, text) {\n if (charIndex <= text.length) {\n updateValue(element, text.substring(0, charIndex) + cursor);\n charIndex++;\n timer = $timeout(function () {\n updateIt(element, charIndex, arrIndex, text);\n }, typeDelay);\n return;\n } else {\n charIndex--;\n\n if($scope.iterationCallback) {\n $scope.iterationCallback()(arrIndex);\n }\n\n // check if it's an array\n if (textArray && arrIndex < textArray.length - 1) {\n timer = $timeout(function () {\n cleanAndRestart(element, charIndex, arrIndex, textArray[arrIndex]);\n }, $scope.iterationDelay);\n } else {\n if ($scope.callbackFn) {\n $scope.callbackFn();\n }\n blinkIt(element, charIndex, currentText);\n }\n }\n }\n\n function blinkIt(element, charIndex) {\n var text = element.text().substring(0, element.text().length - 1);\n if (blinkCursor) {\n if (blinkDelay) {\n auxStyle = '-webkit-animation:blink-it steps(1) ' + blinkDelay + ' infinite;-moz-animation:blink-it steps(1) ' + blinkDelay + ' infinite ' +\n '-ms-animation:blink-it steps(1) ' + blinkDelay + ' infinite;-o-animation:blink-it steps(1) ' + blinkDelay + ' infinite; ' +\n 'animation:blink-it steps(1) ' + blinkDelay + ' infinite;';\n updateValue(element, text.substring(0, charIndex) + '' + cursor + '');\n } else {\n updateValue(element, text.substring(0, charIndex) + '' + cursor + '');\n }\n } else {\n updateValue(element, text.substring(0, charIndex));\n }\n }\n\n function cleanAndRestart(element, charIndex, arrIndex, currentText) {\n if(charIndex == 0) {\n if($scope.prebeginFn) {\n $scope.prebeginFn()();\n }\n }\n if (charIndex > 0) {\n currentText = currentText.slice(0, -1);\n // element.html(currentText.substring(0, currentText.length - 1) + cursor);\n updateValue(element, currentText + cursor);\n charIndex--;\n timer = $timeout(function () {\n cleanAndRestart(element, charIndex, arrIndex, currentText);\n }, eraseDelay);\n return;\n } else {\n arrIndex++;\n currentText = textArray[arrIndex];\n timer = $timeout(function () {\n updateIt(element, 0, arrIndex, currentText);\n }, typeDelay);\n }\n }\n\n function getTypeDelay(delay) {\n if (typeof delay === 'string') {\n return delay.charAt(delay.length - 1) === 's' ? parseInt(delay.substring(0, delay.length - 1), 10) * 1000 : +delay;\n } else {\n return false;\n }\n }\n\n function getAnimationDelay(delay) {\n if (typeof delay === 'string') {\n return delay.charAt(delay.length - 1) === 's' ? delay : parseInt(delay.substring(0, delay.length - 1), 10) / 1000;\n }\n }\n\n function updateValue(element, value) {\n if (element.prop('nodeName').toUpperCase() === 'INPUT') {\n return element.val(value);\n }\n return element.html(value);\n }\n\n $scope.$on('$destroy', function () {\n if (timer) {\n $timeout.cancel(timer);\n }\n });\n\n $scope.$watch('start', function (newVal) {\n if (!running && newVal) {\n running = !running;\n typewrite();\n }\n });\n\n $scope.$watch('text', function (newVal, oldVal) {\n if(!(newVal instanceof Array)) {\n currentText = newVal;\n typewrite();\n }\n });\n }\n\n return {\n restrict: 'A',\n link: linkFunction,\n replace: true,\n scope: {\n text: '=',\n callbackFn: '&',\n iterationCallback: '&',\n iterationDelay: '=',\n prebeginFn: '&',\n start: '='\n }\n };\n\n }]);\n;var Neeto = Neeto || {};\n\nNeeto.crypto = {\n\n generateRandomKey: function() {\n return CryptoJS.lib.WordArray.random(256/8).toString();\n },\n\n decryptText: function(encrypted_content, key) {\n return CryptoJS.AES.decrypt(encrypted_content, key).toString(CryptoJS.enc.Utf8);\n },\n\n encryptText: function(text, key) {\n return CryptoJS.AES.encrypt(text, key).toString();\n },\n\n generateRandomEncryptionKey: function() {\n var salt = Neeto.crypto.generateRandomKey();\n var passphrase = Neeto.crypto.generateRandomKey();\n return CryptoJS.PBKDF2(passphrase, salt, { keySize: 256/32 }).toString();\n },\n\n sha256: function(text) {\n return CryptoJS.SHA256(text).toString();\n },\n\n /** Generates two deterministic 256 bit keys based on one input */\n generateAsymmetricKeyPair: function(input, salt) {\n var output = CryptoJS.PBKDF2(input, salt, { keySize: 512/32, hasher: CryptoJS.algo.SHA512, iterations: 3000 });\n var firstHalf = _.clone(output);\n var secondHalf = _.clone(output);\n var sigBytes = output.sigBytes/2;\n var outputLength = output.words.length;\n firstHalf.words = output.words.slice(0, outputLength/2);\n secondHalf.words = output.words.slice(outputLength/2, outputLength);\n firstHalf.sigBytes = sigBytes;\n secondHalf.sigBytes = sigBytes;\n return [firstHalf.toString(), secondHalf.toString()];\n },\n\n generateEncryptionKeysForUser: function(password, email) {\n var keys = Neeto.crypto.generateAsymmetricKeyPair(password, email);\n var pw = keys[0];\n var gk = keys[1];\n\n return {pw: pw, gk: gk};\n }\n };\n"]} \ No newline at end of file +{"version":3,"sources":["app.js"],"names":["Neeto","angular","module","config","RestangularProvider","apiControllerProvider","setDefaultHeaders","url","defaultServerURL","setBaseUrl","setFullRequestInterceptor","element","operation","route","headers","params","httpConfig","token","localStorage","getItem","_","extend","Authorization","$stateProvider","$urlRouterProvider","$locationProvider","state","abstract","parent","views","templateUrl","controller","resolve","presentation","getPresentation","$rootScope","$stateParams","resetData","reset_password_token","email","$on","event","toState","toParams","fromState","fromParams","options","$q","$state","Restangular","deferred","defer","restangularQuery","one","get","root_path","secondary_path","then","response","catch","go","promise","otherwise","$injector","$location","path","html5Mode","BaseCtrl","modelManager","directive","$timeout","restrict","scope","save","remove","note","user","replace","controllerAs","bindToController","link","elem","attrs","ctrl","handler","ctrlKey","metaKey","String","fromCharCode","which","toLowerCase","preventDefault","saveNote","clickedEditNote","toggleMarkdown","toggleFullScreen","window","addEventListener","removeEventListener","$watch","oldNote","setNote","$sce","apiController","markdownRenderer","demoNotes","title","content","showSampler","id","filteredNotes","length","demoNoteNames","map","currentDemoContent","text","prebeginFn","bind","callback","index","contentCallback","editorMode","focusTitle","hasChanges","dummy","onPreviewDoubleClick","focusEditor","delay","setTimeout","document","getElementById","focus","clickedTextArea","showMenu","renderedContent","renderHtml","renderedContentForText","statusTimeout","$event","success","clearDraft","cancel","noteStatus","saveTitle","target","blur","saveTimeout","changesMade","saveDraftToDisk","contentChanged","nameChanged","onNameFocus","editingName","onContentFocus","$broadcast","editingUrl","onNameBlur","fullscreen","selectedMenuItem","editUrlPressed","publicUrlForNote","base","saveUrl","original","relative_path","updatePresentation","alert","shareNote","openInNewTab","a","createElement","href","click","shareItem","unshareNote","unshareItem","presentationURL","clickedMenu","locked","deleteNote","logout","$auth","serverSideValidation","changePasswordPressed","showNewPasswordForm","accountMenuPressed","serverData","getServer","showAccountMenu","showFaq","changeServer","setServer","signOutPressed","signout","location","reload","submitPasswordChange","passwordChangeData","status","data","password","password_confirmation","changePassword","current_password","new_password","hasLocalData","mergeLocalChanged","shouldMerge","confirm","loginSubmitPressed","loginData","login","user_password","errors","onAuthSuccess","submitRegistrationForm","register","forgotPasswordSubmit","requestPasswordReset","resp","encryptionStatusForNotes","allNotes","countEncrypted","forEach","encryptionEnabled","downloadDataArchive","setAttribute","notesDataFile","importFileSelected","files","file","reader","FileReader","onload","e","importJSONData","result","console","log","readAsText","mergeLocalDataRemotely","showLogin","showRegistration","$scope","bodyClass","description","onUserSet","setUser","defaultUser","allTag","Tag","all","name","tags","getCurrentUser","User","items","json_obj","Item","localUser","updateAllTag","notes","tagsWillMakeSelection","tag","tagsSelectionMade","selectedTag","tagsAddNew","addTag","tagsSave","saveItems","tagsUpdateNoteTag","noteCopy","newTag","oldTag","originalNote","find","uuid","removeTagFromNote","addTagToNote","saveDirtyItems","notesRemoveTag","validNotes","Note","filterDummyNotes","deleteItem","notesSelectionMade","selectedNote","notesAddNew","addNote","unshift","addDirtyItems","headerLogout","addNew","selectionMade","removeTag","tagDidChange","ngDialog","isFirstLoad","noteFilter","setNotes","draft","getDraft","selectNote","createNewNote","selectedTagDelete","selectedTagShare","username","open","template","className","disableAnimation","selectedTagUnshare","publicUrlForTag","createNew","visible","selectFirstNote","visibleNotes","filter","newNote","filterNotes","includes","filterTextChanged","willSelect","updateNoteTag","newTags","setTags","setAllTag","initialLoad","selectTag","clickedAddNewTag","editingTag","crypto","generateRandomKey","originalTagName","onTagTitleFocus","tagTitleDidChange","saveTag","savedTag","merge","noteCount","handleDrop","formData","saveUsername","setUsername","closeThisDialog","Object","defineProperty","set","value","finalValue","decodedValue","JSON","parse","enumerable","generateUUID","setContentRaw","rawContent","references","reference","push","uniq","contentType","content_type","loc_eek","hasOnePublicTag","hasPublicTag","isPublic","filtered","referencesMatchingContentType","provider","domainName","domain_comps","hostname","split","domain","protocol","port","$get","ApiController","refresh","setItem","plain","decryptItemsWithLocalKey","error","keys","generateEncryptionKeysForUser","setGk","gk","request","pw","post","current_keys","new_keys","_performPasswordChange","reencryptAllItemsAndSave","patch","verifyEncryptionStatusOfAllItems","allItems","filteredItems","itemsNeedingUpdate","item","isEncrypted","saveBatchItems","dirtyItems","clearDirtyItems","createRequestParamsForItem","savedItems","itemCopy","cloneDeep","encryptSingleItem","retrieveGk","stringify","writeUserToLocalStorage","resource","nil","jsonString","encryptSingleItemWithLocalKey","itemsDataFile","textFile","makeTextFile","Blob","type","URL","revokeObjectURL","createObjectURL","presentationParams","presentable_type","presentable_id","created_at","modified_at","tag_id","tag_name","removeItem","staticifyObject","object","saveUser","filterDummyItems","writeToLocalStorage","key","toJson","draftString","ek","decryptText","generateRandomEncryptionKey","encryptText","local_encryption_scheme","encryptItems","encryptItemsWithLocalKey","encryptNonPublicItemsWithLocalKey","nonpublic","pending_share","decryptSingleItemWithLocalKey","decryptSingleItem","local_eek","decryptItems","newKey","oldKey","ItemManager","itemId","referencesForItemId","referencedItem","removeReferencesBetweenItems","itemOne","itemTwo","removeReference","addReference","_items","resolveReferences","service","marked","setOptions","breaks","sanitize","html_code","trustAsHtml","ModelManager","groups","Array","concat","dirty","createReferencesBetweenItems","refreshRelationshipsForTag","refreshRelationshipsForNote","sort","b","Date","itemsForContentType","updateReferencesLocalMapping","showErrors","formErrors","form","$setDirty","$setValidity","$error","server","join","parseErrors","shouldFocus","$element","el","draggable","dataTransfer","effectAllowed","setData","classList","add","drop","bin","dropEffect","counter","stopPropagation","binId","getData","$apply","fn","on","require","modelCtrl","lowercase","inputValue","undefined","lowercased","$setViewValue","$render","$parsers","ngModel","$window","getSelection","toString","setSelectionRange","linkFunction","$attrs","timer","initialDelay","getTypeDelay","typeDelay","eraseDelay","blinkDelay","getAnimationDelay","cursor","blinkCursor","currentText","textArray","running","auxStyle","start","typewrite","updateIt","charIndex","arrIndex","updateValue","substring","iterationCallback","cleanAndRestart","iterationDelay","callbackFn","blinkIt","slice","charAt","parseInt","prop","toUpperCase","val","html","newVal","oldVal","CryptoJS","lib","WordArray","random","d","getTime","performance","now","c","r","Math","floor","encrypted_content","AES","decrypt","enc","Utf8","encrypt","salt","passphrase","PBKDF2","keySize","sha256","SHA256","generateAsymmetricKeyPair","input","output","hasher","algo","SHA512","iterations","firstHalf","clone","secondHalf","sigBytes","outputLength","words"],"mappings":"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","file":"transpiled.js","sourcesContent":["'use strict';\n\nvar Neeto = Neeto || {};\n\nangular\n .module('app.frontend', [\n 'ui.router',\n 'ng-token-auth',\n 'restangular',\n 'ipCookie',\n 'oc.lazyLoad',\n 'angularLazyImg',\n 'ngDialog'\n ])\n // Configure path to API\n .config(function (RestangularProvider, apiControllerProvider) {\n RestangularProvider.setDefaultHeaders({\"Content-Type\": \"application/json\"});\n\n var url = apiControllerProvider.defaultServerURL();\n RestangularProvider.setBaseUrl(url);\n\n RestangularProvider.setFullRequestInterceptor(function(element, operation, route, url, headers, params, httpConfig) {\n var token = localStorage.getItem(\"jwt\");\n if(token) {\n headers = _.extend(headers, {Authorization: \"Bearer \" + localStorage.getItem(\"jwt\")});\n }\n\n return {\n element: element,\n params: params,\n headers: headers,\n httpConfig: httpConfig\n };\n });\n })\n;angular.module('app.frontend')\n .config(function ($stateProvider, $urlRouterProvider, $locationProvider) {\n\n $stateProvider\n .state('base', {\n abstract: true,\n })\n\n // Homepage\n .state('home', {\n url: '/',\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/home.html',\n controller: 'HomeCtrl'\n }\n }\n })\n\n .state('presentation', {\n url: '/:root_path',\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/presentation.html',\n controller: \"PresentationCtrl\"\n }\n },\n resolve: {\n presentation: getPresentation\n }\n })\n\n .state('tag', {\n url: '/:root_path/:secondary_path',\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/presentation.html',\n controller: \"PresentationCtrl\"\n }\n },\n resolve: {\n presentation: getPresentation\n }\n })\n\n // Auth routes\n .state('auth', {\n abstract: true,\n url: '/auth',\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/auth/wrapper.html',\n }\n }\n })\n .state('auth.login', {\n url: '/login',\n templateUrl: 'frontend/auth/login.html',\n })\n .state('auth.forgot', {\n url: '/forgot',\n templateUrl: 'frontend/auth/forgot.html',\n })\n .state('auth.reset', {\n url: '/reset?reset_password_token&email',\n templateUrl: 'frontend/auth/reset.html',\n controller: function($rootScope, $stateParams) {\n $rootScope.resetData = {reset_password_token: $stateParams.reset_password_token, email: $stateParams.email};\n\n // Clear reset_password_token on change state\n $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options) {\n $rootScope.reset_password_token = null;\n });\n },\n })\n\n\n // 404 Error\n .state('404', {\n parent: 'base',\n views: {\n 'content@' : {\n templateUrl: 'frontend/errors/404.html'\n }\n }\n });\n\n function getPresentation ($q, $state, $stateParams, Restangular) {\n var deferred = $q.defer();\n var restangularQuery = Restangular.one('presentations', 'show_by_path');\n restangularQuery.get({root_path: $stateParams.root_path, secondary_path: $stateParams.secondary_path})\n .then(function(response) {\n deferred.resolve(response);\n })\n .catch(function(response) {\n $state.go('404');\n });\n\n return deferred.promise;\n }\n\n // Default fall back route\n $urlRouterProvider.otherwise(function($injector, $location){\n var state = $injector.get('$state');\n state.go('404');\n return $location.path();\n });\n\n // enable HTML5 Mode for SEO\n $locationProvider.html5Mode(true);\n\n });\n;class BaseCtrl {\n constructor($rootScope, modelManager) {\n // $rootScope.resetPasswordSubmit = function() {\n // var new_keys = Neeto.crypto.generateEncryptionKeysForUser($rootScope.resetData.password, $rootScope.resetData.email);\n // var data = _.clone($rootScope.resetData);\n // data.password = new_keys.pw;\n // data.password_confirmation = new_keys.pw;\n // $auth.updatePassword(data);\n // apiController.setGk(new_keys.gk);\n // }\n\n // var note = new Note();\n // note.content = {title: \"hello\", text: \"world\"};\n // console.log(\"note content\", note.content);\n // console.log(\"note title\", note.title);\n // console.log(\"note json\", JSON.stringify(note));\n //\n // console.log(\"Copy\", _.cloneDeep(note));\n }\n}\n\nangular.module('app.frontend').controller('BaseCtrl', BaseCtrl);\n;angular.module('app.frontend')\n .directive(\"editorSection\", function($timeout){\n return {\n restrict: 'E',\n scope: {\n save: \"&\",\n remove: \"&\",\n note: \"=\",\n user: \"=\"\n },\n templateUrl: 'frontend/editor.html',\n replace: true,\n controller: 'EditorCtrl',\n controllerAs: 'ctrl',\n bindToController: true,\n\n link:function(scope, elem, attrs, ctrl) {\n\n var handler = function(event) {\n if (event.ctrlKey || event.metaKey) {\n switch (String.fromCharCode(event.which).toLowerCase()) {\n case 's':\n event.preventDefault();\n $timeout(function(){\n ctrl.saveNote(event);\n });\n break;\n case 'e':\n event.preventDefault();\n $timeout(function(){\n ctrl.clickedEditNote();\n })\n break;\n case 'm':\n event.preventDefault();\n $timeout(function(){\n ctrl.toggleMarkdown();\n })\n break;\n case 'o':\n event.preventDefault();\n $timeout(function(){\n ctrl.toggleFullScreen();\n })\n break;\n }\n }\n };\n\n window.addEventListener('keydown', handler);\n\n scope.$on('$destroy', function(){\n window.removeEventListener('keydown', handler);\n })\n\n scope.$watch('ctrl.note', function(note, oldNote){\n if(note) {\n ctrl.setNote(note, oldNote);\n } else {\n ctrl.note = {};\n }\n });\n }\n }\n })\n .controller('EditorCtrl', function ($sce, $timeout, apiController, modelManager, markdownRenderer, $rootScope) {\n\n this.demoNotes = [\n {title: \"Live print a file with tail\", content: \"tail -f log/production.log\"},\n {title: \"Create SSH tunnel\", content: \"ssh -i .ssh/key.pem -N -L 3306:example.com:3306 ec2-user@example.com\"},\n {title: \"List of processes running on port\", content: \"lsof -i:8080\"},\n {title: \"Set ENV from file\", content: \"export $(cat .envfile | xargs)\"},\n {title: \"Find process by name\", content: \"ps -ax | grep \"},\n {title: \"NPM install without sudo\", content: \"sudo chown -R $(whoami) ~/.npm\"},\n {title: \"Email validation regex\", content: \"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$\"},\n {title: \"Ruby generate 256 bit key\", content: \"Digest::SHA256.hexdigest(SecureRandom.random_bytes(32))\"},\n {title: \"Mac add user to user tag\", content: \"sudo dsedittag -o edit -a USERNAME -t user GROUPNAME\"},\n {title: \"Kill Mac OS System Apache\", content: \"sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist\"},\n {title: \"Docker run with mount binding and port\", content: \"docker run -v /home/vagrant/www/app:/var/www/app -p 8080:80 -d kpi/s3\"},\n {title: \"MySQL grant privileges\", content: \"GRANT [type of permission] ON [database name].[table name] TO ‘[username]’@'%’;\"},\n {title: \"MySQL list users\", content: \"SELECT User FROM mysql.user;\"},\n ];\n\n this.showSampler = !this.user.id && modelManager.filteredNotes.length == 0;\n\n this.demoNoteNames = _.map(this.demoNotes, function(note){\n return note.title;\n });\n\n this.currentDemoContent = {text: null};\n\n this.prebeginFn = function() {\n this.currentDemoContent.text = null;\n }.bind(this)\n\n this.callback = function(index) {\n this.currentDemoContent.text = this.demoNotes[index].text;\n }.bind(this)\n\n this.contentCallback = function(index) {\n }\n\n this.setNote = function(note, oldNote) {\n this.editorMode = 'edit';\n if(note.content.text.length == 0) {\n this.focusTitle(100);\n }\n\n if(oldNote && oldNote != note) {\n if(oldNote.hasChanges) {\n this.save()(oldNote, null);\n } else if(oldNote.dummy) {\n this.remove()(oldNote);\n }\n }\n }\n\n this.onPreviewDoubleClick = function() {\n this.editorMode = 'edit';\n this.focusEditor(100);\n }\n\n this.focusEditor = function(delay) {\n setTimeout(function(){\n var element = document.getElementById(\"note-text-editor\");\n element.focus();\n }, delay)\n }\n\n this.focusTitle = function(delay) {\n setTimeout(function(){\n document.getElementById(\"note-title-editor\").focus();\n }, delay)\n }\n\n this.clickedTextArea = function() {\n this.showMenu = false;\n }\n\n this.renderedContent = function() {\n return markdownRenderer.renderHtml(markdownRenderer.renderedContentForText(this.note.content.text));\n }\n\n var statusTimeout;\n\n this.saveNote = function($event) {\n var note = this.note;\n note.dummy = false;\n this.save()(note, function(success){\n if(success) {\n apiController.clearDraft();\n\n if(statusTimeout) $timeout.cancel(statusTimeout);\n statusTimeout = $timeout(function(){\n this.noteStatus = \"All changes saved\"\n }.bind(this), 200)\n }\n }.bind(this));\n }\n\n this.saveTitle = function($event) {\n $event.target.blur();\n this.saveNote($event);\n this.focusEditor();\n }\n\n var saveTimeout;\n this.changesMade = function() {\n this.note.hasChanges = true;\n this.note.dummy = false;\n apiController.saveDraftToDisk(this.note);\n\n if(saveTimeout) $timeout.cancel(saveTimeout);\n if(statusTimeout) $timeout.cancel(statusTimeout);\n saveTimeout = $timeout(function(){\n this.noteStatus = \"Saving...\";\n this.saveNote();\n }.bind(this), 150)\n }\n\n\n this.contentChanged = function() {\n this.changesMade();\n }\n\n this.nameChanged = function() {\n this.changesMade();\n }\n\n this.onNameFocus = function() {\n this.editingName = true;\n }\n\n this.onContentFocus = function() {\n this.showSampler = false;\n $rootScope.$broadcast(\"editorFocused\");\n this.editingUrl = false;\n }\n\n this.onNameBlur = function() {\n this.editingName = false;\n }\n\n this.toggleFullScreen = function() {\n this.fullscreen = !this.fullscreen;\n if(this.fullscreen) {\n if(this.editorMode == 'edit') {\n // refocus\n this.focusEditor(0);\n }\n } else {\n\n }\n }\n\n this.selectedMenuItem = function() {\n this.showMenu = false;\n }\n\n this.toggleMarkdown = function() {\n if(this.editorMode == 'preview') {\n this.editorMode = 'edit';\n } else {\n this.editorMode = 'preview';\n }\n }\n\n this.editUrlPressed = function() {\n this.showMenu = false;\n var url = this.publicUrlForNote(this.note);\n url = url.replace(this.note.presentation.root_path, \"\");\n this.url = {base: url, token : this.note.presentation.root_path};\n this.editingUrl = true;\n }\n\n this.saveUrl = function($event) {\n $event.target.blur();\n\n var original = this.note.presentation.relative_path;\n this.note.presentation.relative_path = this.url.token;\n\n apiController.updatePresentation(this.note, this.note.presentation, function(response){\n if(!response) {\n this.note.presentation.relative_path = original;\n this.url.token = original;\n alert(\"This URL is not available.\");\n } else {\n this.editingUrl = false;\n }\n }.bind(this))\n }\n\n this.shareNote = function() {\n\n function openInNewTab(url) {\n var a = document.createElement(\"a\");\n a.target = \"_blank\";\n a.href = url;\n a.click();\n }\n\n apiController.shareItem(this.user, this.note, function(note){\n openInNewTab(this.publicUrlForNote(note));\n }.bind(this))\n this.showMenu = false;\n }\n\n this.unshareNote = function() {\n apiController.unshareItem(this.user, this.note, function(note){\n\n })\n this.showMenu = false;\n }\n\n this.publicUrlForNote = function() {\n return this.note.presentationURL();\n }\n\n this.clickedMenu = function() {\n if(this.note.locked) {\n alert(\"This note has been shared without an account, and can therefore not be changed.\")\n } else {\n this.showMenu = !this.showMenu;\n }\n }\n\n this.deleteNote = function() {\n apiController.clearDraft();\n this.remove()(this.note);\n this.showMenu = false;\n }\n\n this.clickedEditNote = function() {\n this.editorMode = 'edit';\n this.focusEditor(100);\n }\n\n });\n;angular.module('app.frontend')\n .directive(\"header\", function(){\n return {\n restrict: 'E',\n scope: {\n user: \"=\",\n logout: \"&\"\n },\n templateUrl: 'frontend/header.html',\n replace: true,\n controller: 'HeaderCtrl',\n controllerAs: 'ctrl',\n bindToController: true,\n\n link:function(scope, elem, attrs, ctrl) {\n\n }\n }\n })\n .controller('HeaderCtrl', function ($auth, $state, apiController, modelManager, serverSideValidation, $timeout) {\n\n this.changePasswordPressed = function() {\n this.showNewPasswordForm = !this.showNewPasswordForm;\n }\n\n this.accountMenuPressed = function() {\n this.serverData = {url: apiController.getServer()};\n this.showAccountMenu = !this.showAccountMenu;\n this.showFaq = false;\n this.showNewPasswordForm = false;\n }\n\n this.changeServer = function() {\n apiController.setServer(this.serverData.url, true);\n }\n\n this.signOutPressed = function() {\n this.showAccountMenu = false;\n this.logout()();\n apiController.signout();\n window.location.reload();\n }\n\n this.submitPasswordChange = function() {\n this.passwordChangeData.status = \"Generating New Keys...\";\n\n $timeout(function(){\n if(data.password != data.password_confirmation) {\n alert(\"Your new password does not match its confirmation.\");\n return;\n }\n\n apiController.changePassword(this.user, this.passwordChangeData.current_password, this.passwordChangeData.new_password, function(response){\n\n })\n\n }.bind(this))\n }\n\n this.hasLocalData = function() {\n return modelManager.filteredNotes.length > 0;\n }\n\n this.mergeLocalChanged = function() {\n if(!this.user.shouldMerge) {\n if(!confirm(\"Unchecking this option means any locally stored tags and notes you have now will be deleted. Are you sure you want to continue?\")) {\n this.user.shouldMerge = true;\n }\n }\n }\n\n this.loginSubmitPressed = function() {\n this.loginData.status = \"Generating Login Keys...\";\n $timeout(function(){\n apiController.login(this.loginData.email, this.loginData.user_password, function(response){\n if(response.errors) {\n this.loginData.status = response.errors[0];\n } else {\n this.onAuthSuccess(response.user);\n }\n }.bind(this));\n }.bind(this))\n }\n\n this.submitRegistrationForm = function() {\n this.loginData.status = \"Generating Account Keys...\";\n\n $timeout(function(){\n apiController.register(this.loginData.email, this.loginData.user_password, function(response){\n if(response.errors) {\n this.loginData.status = response.errors[0];\n } else {\n this.onAuthSuccess(response.user);\n }\n }.bind(this));\n }.bind(this))\n }\n\n this.forgotPasswordSubmit = function() {\n $auth.requestPasswordReset(this.resetData)\n .then(function(resp) {\n this.resetData.response = \"Success\";\n // handle success response\n }.bind(this))\n .catch(function(resp) {\n // handle error response\n this.resetData.response = \"Error\";\n }.bind(this));\n }\n\n this.encryptionStatusForNotes = function() {\n var allNotes = modelManager.filteredNotes;\n var countEncrypted = 0;\n allNotes.forEach(function(note){\n if(note.encryptionEnabled()) {\n countEncrypted++;\n }\n }.bind(this))\n\n return countEncrypted + \"/\" + allNotes.length + \" notes encrypted\";\n }\n\n this.downloadDataArchive = function() {\n var link = document.createElement('a');\n link.setAttribute('download', 'neeto.json');\n link.href = apiController.notesDataFile(this.user);\n link.click();\n }\n\n this.importFileSelected = function(files) {\n var file = files[0];\n var reader = new FileReader();\n reader.onload = function(e) {\n apiController.importJSONData(e.target.result, function(success, response){\n console.log(\"import response\", success, response);\n if(success) {\n // window.location.reload();\n } else {\n alert(\"There was an error importing your data. Please try again.\");\n }\n })\n }\n reader.readAsText(file);\n }\n\n this.onAuthSuccess = function(user) {\n this.user.id = user.id;\n\n if(this.user.shouldMerge && this.hasLocalData()) {\n apiController.mergeLocalDataRemotely(this.user, function(){\n window.location.reload();\n });\n } else {\n window.location.reload();\n }\n\n this.showLogin = false;\n this.showRegistration = false;\n }\n\n });\n;angular.module('app.frontend')\n.controller('HomeCtrl', function ($scope, $rootScope, $timeout, apiController, modelManager) {\n $rootScope.bodyClass = \"app-body-class\";\n $rootScope.title = \"Notes — Neeto, a secure code box for developers\";\n $rootScope.description = \"A secure code box for developers to store common commands and useful notes.\";\n\n var onUserSet = function() {\n apiController.setUser($scope.defaultUser);\n $scope.allTag = new Tag({all: true});\n $scope.allTag.content.name = \"All\";\n $scope.tags = modelManager.tags;\n\n // apiController.verifyEncryptionStatusOfAllItems($scope.defaultUser, function(success){});\n }\n\n apiController.getCurrentUser(function(response){\n if(response && !response.errors) {\n console.log(\"Get user response\", response);\n $scope.defaultUser = new User(response);\n modelManager.items = _.map(response.items, function(json_obj){return new Item(json_obj)});\n $rootScope.title = \"Notes — Neeto\";\n onUserSet();\n } else {\n $scope.defaultUser = new User(apiController.localUser());\n onUserSet();\n }\n });\n\n /*\n Tags Ctrl Callbacks\n */\n\n $scope.updateAllTag = function() {\n $scope.allTag.notes = modelManager.filteredNotes;\n }\n\n $scope.tagsWillMakeSelection = function(tag) {\n if(tag.all) {\n $scope.updateAllTag();\n }\n }\n\n $scope.tagsSelectionMade = function(tag) {\n if(!tag.notes) {\n tag.notes = [];\n }\n $scope.selectedTag = tag;\n }\n\n $scope.tagsAddNew = function(tag) {\n modelManager.addTag(tag);\n }\n\n $scope.tagsSave = function(tag, callback) {\n apiController.saveItems([tag], callback);\n }\n\n /*\n Called to update the tag of a note after drag and drop change\n The note object is a copy of the original\n */\n $scope.tagsUpdateNoteTag = function(noteCopy, newTag, oldTag) {\n\n var originalNote = _.find($scope.defaultUser.notes, {uuid: noteCopy.uuid});\n modelManager.removeTagFromNote(oldTag, originalNote);\n if(!newTag.all) {\n modelManager.addTagToNote(newTag, originalNote);\n }\n\n apiController.saveDirtyItems(function(){});\n }\n\n /*\n Notes Ctrl Callbacks\n */\n\n $scope.notesRemoveTag = function(tag) {\n var validNotes = Note.filterDummyNotes(tag.notes);\n if(validNotes == 0) {\n // if no more notes, delete tag\n apiController.deleteItem($scope.defaultUser, tag, function(){\n // force scope tags to update on sub directives\n $scope.tags = [];\n $timeout(function(){\n $scope.tags = modelManager.tags;\n })\n });\n } else {\n alert(\"To delete this tag, remove all its notes first.\");\n }\n }\n\n $scope.notesSelectionMade = function(note) {\n $scope.selectedNote = note;\n }\n\n $scope.notesAddNew = function(note) {\n modelManager.addNote(note);\n\n if(!$scope.selectedTag.all) {\n console.log(\"add tag\");\n modelManager.addTagToNote($scope.selectedTag, note);\n } else {\n $scope.selectedTag.notes.unshift(note);\n }\n }\n\n /*\n Shared Callbacks\n */\n\n $scope.saveNote = function(note, callback) {\n modelManager.addDirtyItems(note);\n\n apiController.saveDirtyItems(function(){\n modelManager.addNote(note);\n note.hasChanges = false;\n\n if(callback) {\n callback(true);\n }\n })\n }\n\n $scope.deleteNote = function(note) {\n\n modelManager.deleteNote(note);\n\n if(note == $scope.selectedNote) {\n $scope.selectedNote = null;\n }\n\n if(note.dummy) {\n return;\n }\n\n apiController.deleteItem($scope.defaultUser, note, function(success){})\n apiController.saveDirtyItems(function(){});\n }\n\n /*\n Header Ctrl Callbacks\n */\n\n $scope.headerLogout = function() {\n $scope.defaultUser = apiController.localUser();\n $scope.tags = $scope.defaultUser.tags;\n }\n\n\n});\n;angular.module('app.frontend')\n .directive(\"notesSection\", function(){\n return {\n scope: {\n addNew: \"&\",\n selectionMade: \"&\",\n remove: \"&\",\n tag: \"=\",\n user: \"=\",\n removeTag: \"&\"\n },\n\n templateUrl: 'frontend/notes.html',\n replace: true,\n controller: 'NotesCtrl',\n controllerAs: 'ctrl',\n bindToController: true,\n\n link:function(scope, elem, attrs, ctrl) {\n scope.$watch('ctrl.tag', function(tag, oldTag){\n if(tag) {\n ctrl.tagDidChange(tag, oldTag);\n }\n });\n }\n }\n })\n .controller('NotesCtrl', function (apiController, modelManager, $timeout, ngDialog, $rootScope) {\n\n $rootScope.$on(\"editorFocused\", function(){\n this.showMenu = false;\n }.bind(this))\n\n var isFirstLoad = true;\n\n this.tagDidChange = function(tag, oldTag) {\n this.showMenu = false;\n\n if(this.selectedNote && this.selectedNote.dummy) {\n _.remove(oldTag.notes, this.selectedNote);\n }\n\n this.noteFilter.text = \"\";\n this.setNotes(tag.notes, false);\n\n if(isFirstLoad) {\n $timeout(function(){\n var draft = apiController.getDraft();\n if(draft) {\n var note = draft;\n this.selectNote(note);\n } else {\n this.createNewNote();\n isFirstLoad = false;\n }\n }.bind(this))\n } else if(tag.notes.length == 0) {\n this.createNewNote();\n }\n }\n\n this.selectedTagDelete = function() {\n this.showMenu = false;\n this.removeTag()(this.tag);\n }\n\n this.selectedTagShare = function() {\n this.showMenu = false;\n\n if(!this.user.id) {\n alert(\"You must be signed in to share a tag.\");\n return;\n }\n\n if(this.tag.all) {\n alert(\"You cannot share the 'All' tag.\");\n return;\n }\n\n var callback = function(username) {\n apiController.shareItem(this.user, this.tag, function(response){\n })\n }.bind(this);\n\n if(!this.user.username) {\n ngDialog.open({\n template: 'frontend/modals/username.html',\n controller: 'UsernameModalCtrl',\n resolve: {\n user: function() {return this.user}.bind(this),\n callback: function() {return callback}\n },\n className: 'ngdialog-theme-default',\n disableAnimation: true\n });\n } else {\n callback(this.user.username);\n }\n }\n\n this.selectedTagUnshare = function() {\n this.showMenu = false;\n apiController.unshareItem(this.user, this.tag, function(response){\n\n })\n }\n\n this.publicUrlForTag = function() {\n return this.tag.presentation.url;\n }\n\n this.setNotes = function(notes, createNew) {\n this.notes = notes;\n console.log(\"set notes\", notes);\n notes.forEach(function(note){\n note.visible = true;\n })\n this.selectFirstNote(createNew);\n }\n\n this.selectFirstNote = function(createNew) {\n var visibleNotes = this.notes.filter(function(note){\n return note.visible;\n });\n\n if(visibleNotes.length > 0) {\n this.selectNote(visibleNotes[0]);\n } else if(createNew) {\n this.createNewNote();\n }\n }\n\n this.selectNote = function(note) {\n this.selectedNote = note;\n this.selectionMade()(note);\n }\n\n this.createNewNote = function() {\n var title = \"New Note\" + (this.notes ? (\" \" + (this.notes.length + 1)) : \"\");\n this.newNote = new Note({dummy: true});\n this.newNote.content.title = title;\n if(this.tag && !this.tag.all) {\n modelManager.addTagToNote(this.tag, this.newNote);\n }\n this.selectNote(this.newNote);\n this.addNew()(this.newNote);\n }\n\n this.noteFilter = {text : ''};\n\n this.filterNotes = function(note) {\n if(this.noteFilter.text.length == 0) {\n note.visible = true;\n } else {\n note.visible = note.title.toLowerCase().includes(this.noteFilter.text) || note.text.toLowerCase().includes(this.noteFilter.text);\n }\n return note.visible;\n }.bind(this)\n\n this.filterTextChanged = function() {\n $timeout(function(){\n if(!this.selectedNote.visible) {\n this.selectFirstNote(false);\n }\n }.bind(this), 100)\n }\n });\n;angular.module('app.frontend')\n .directive(\"tagsSection\", function(){\n return {\n restrict: 'E',\n scope: {\n addNew: \"&\",\n selectionMade: \"&\",\n willSelect: \"&\",\n save: \"&\",\n tags: \"=\",\n allTag: \"=\",\n user: \"=\",\n updateNoteTag: \"&\"\n },\n templateUrl: 'frontend/tags.html',\n replace: true,\n controller: 'TagsCtrl',\n controllerAs: 'ctrl',\n bindToController: true,\n\n link:function(scope, elem, attrs, ctrl) {\n scope.$watch('ctrl.tags', function(newTags){\n if(newTags) {\n ctrl.setTags(newTags);\n }\n });\n\n scope.$watch('ctrl.allTag', function(allTag){\n if(allTag) {\n ctrl.setAllTag(allTag);\n }\n });\n }\n }\n })\n .controller('TagsCtrl', function () {\n\n var initialLoad = true;\n\n this.setAllTag = function(allTag) {\n this.selectTag(this.allTag);\n }\n\n this.setTags = function(tags) {\n if(initialLoad) {\n initialLoad = false;\n this.selectTag(this.allTag);\n } else {\n if(tags && tags.length > 0) {\n this.selectTag(tags[0]);\n }\n }\n }\n\n this.selectTag = function(tag) {\n this.willSelect()(tag);\n this.selectedTag = tag;\n this.selectionMade()(tag);\n }\n\n this.clickedAddNewTag = function() {\n if(this.editingTag) {\n return;\n }\n\n this.newTag = new Tag({notes : []});\n if(!this.user.uuid) {\n this.newTag.uuid = Neeto.crypto.generateRandomKey()\n }\n this.selectedTag = this.newTag;\n this.editingTag = this.newTag;\n this.addNew()(this.newTag);\n }\n\n var originalTagName = \"\";\n this.onTagTitleFocus = function(tag) {\n originalTagName = tag.content.name;\n }\n\n this.tagTitleDidChange = function(tag) {\n this.editingTag = tag;\n }\n\n this.saveTag = function($event, tag) {\n this.editingTag = null;\n if(tag.content.name.length == 0) {\n tag.content.name = originalTagName;\n originalTagName = \"\";\n return;\n }\n\n $event.target.blur();\n if(!tag.content.name || tag.content.name.length == 0) {\n return;\n }\n\n this.save()(tag, function(savedTag){\n _.merge(tag, savedTag);\n this.selectTag(tag);\n this.newTag = null;\n }.bind(this));\n }\n\n this.noteCount = function(tag) {\n var validNotes = Note.filterDummyNotes(tag.notes);\n return validNotes.length;\n }\n\n this.handleDrop = function(e, newTag, note) {\n this.updateNoteTag()(note, newTag, this.selectedTag);\n }.bind(this)\n\n\n });\n;angular.module('app.frontend')\n.controller('UsernameModalCtrl', function ($scope, apiController, Restangular, user, callback, $timeout) {\n $scope.formData = {};\n\n $scope.saveUsername = function() {\n apiController.setUsername(user, $scope.formData.username, function(response){\n var username = response.root_path;\n user.presentation = response;\n callback(username);\n $scope.closeThisDialog();\n })\n }\n});\n;class Item {\n constructor(json_obj) {\n\n var content;\n\n Object.defineProperty(this, \"content\", {\n get: function() {\n return content;\n },\n set: function(value) {\n var finalValue = value;\n\n if(typeof value === 'string') {\n try {\n var decodedValue = JSON.parse(value);\n finalValue = decodedValue;\n }\n catch(e) {\n finalValue = value;\n }\n }\n content = finalValue;\n },\n enumerable: true,\n });\n\n _.merge(this, json_obj);\n\n if(!this.uuid) {\n this.uuid = Neeto.crypto.generateUUID();\n }\n\n this.setContentRaw = function(rawContent) {\n content = rawContent;\n }\n\n if(!this.content) {\n this.content = {};\n }\n\n if(!this.content.references) {\n this.content.references = [];\n }\n }\n\n addReference(reference) {\n this.content.references.push(reference);\n this.content.references = _.uniq(this.content.references);\n }\n\n removeReference(reference) {\n _.remove(this.content.references, _.find(this.content.references, {uuid: reference.uuid}));\n }\n\n referencesMatchingContentType(contentType) {\n return this.content.references.filter(function(reference){\n return reference.content_type == contentType;\n });\n }\n\n updateReferencesLocalMapping() {\n // should be overriden to manage local properties\n }\n\n /* Returns true if note is shared individually or via tag */\n isPublic() {\n return this.presentation;\n }\n\n isEncrypted() {\n return this.encryptionEnabled() && typeof this.content === 'string' ? true : false;\n }\n\n encryptionEnabled() {\n return this.loc_eek;\n }\n\n presentationURL() {\n return this.presentation.url;\n }\n\n}\n;class Note extends Item {\n\n constructor(json_obj) {\n super(json_obj);\n\n if(!this.tags) {\n this.tags = [];\n }\n\n if(!this.content.title) {\n this.content.title = \"\";\n this.content.text = \"\";\n }\n }\n\n static filterDummyNotes(notes) {\n var filtered = notes.filter(function(note){return note.dummy == false || note.dummy == null});\n return filtered;\n }\n\n get hasOnePublicTag() {\n var hasPublicTag = false;\n this.tags.forEach(function(tag){\n if(tag.isPublic()) {\n hasPublicTag = true;\n return;\n }\n })\n\n return hasPublicTag;\n }\n\n isPublic() {\n return super.isPublic() || this.hasOnePublicTag;\n }\n\n get content_type() {\n return \"Note\";\n }\n}\n;class Tag extends Item {\n\n constructor(json_obj) {\n super(json_obj);\n\n if(!this.notes) {\n this.notes = [];\n }\n\n if(!this.content.name) {\n this.content.name = \"\";\n }\n }\n\n get content_type() {\n return \"Tag\";\n }\n\n updateReferencesLocalMapping() {\n super.updateReferencesLocalMapping();\n this.notes = this.referencesMatchingContentType(\"Note\");\n console.log(\"notes after maping\", this.notes);\n }\n}\n;class User {\n constructor(json_obj) {\n _.merge(this, json_obj);\n }\n}\n;angular.module('app.frontend')\n .provider('apiController', function () {\n\n function domainName() {\n var domain_comps = location.hostname.split(\".\");\n var domain = domain_comps[domain_comps.length - 2] + \".\" + domain_comps[domain_comps.length - 1];\n return domain;\n }\n\n var url;\n\n this.defaultServerURL = function() {\n if(!url) {\n url = localStorage.getItem(\"server\");\n if(!url) {\n url = location.protocol + \"//\" + domainName() + (location.port ? ':' + location.port: '');\n }\n }\n return url;\n }\n\n\n this.$get = function(Restangular, modelManager) {\n return new ApiController(Restangular, modelManager);\n }\n\n function ApiController(Restangular, modelManager) {\n\n this.setUser = function(user) {\n this.user = user;\n }\n\n /*\n Config\n */\n\n this.getServer = function() {\n if(!url) {\n url = localStorage.getItem(\"server\");\n if(!url) {\n url = location.protocol + \"//\" + domainName() + (location.port ? ':' + location.port: '');\n this.setServer(url);\n }\n }\n return url;\n }\n\n this.setServer = function(url, refresh) {\n localStorage.setItem(\"server\", url);\n if(refresh) {\n window.location.reload();\n }\n }\n\n\n /*\n Auth\n */\n\n this.getCurrentUser = function(callback) {\n if(!localStorage.getItem(\"jwt\")) {\n callback(null);\n return;\n }\n Restangular.one(\"users/current\").get().then(function(response){\n var plain = response.plain();\n var items = plain.items;\n this.decryptItemsWithLocalKey(items);\n callback(plain);\n }.bind(this))\n .catch(function(error){\n callback(null);\n })\n }\n\n this.login = function(email, password, callback) {\n var keys = Neeto.crypto.generateEncryptionKeysForUser(password, email);\n this.setGk(keys.gk);\n var request = Restangular.one(\"auth/sign_in.json\");\n request.user = {password: keys.pw, email: email};\n request.post().then(function(response){\n localStorage.setItem(\"jwt\", response.token);\n callback(response);\n })\n }\n\n this.register = function(email, password, callback) {\n var keys = Neeto.crypto.generateEncryptionKeysForUser(password, email);\n this.setGk(keys.gk);\n var request = Restangular.one(\"auth.json\");\n request.user = {password: keys.pw, email: email};\n request.post().then(function(response){\n localStorage.setItem(\"jwt\", response.token);\n callback(response);\n })\n }\n\n this.changePassword = function(user, current_password, new_password) {\n var current_keys = Neeto.crypto.generateEncryptionKeysForUser(current_password, user.email);\n var new_keys = Neeto.crypto.generateEncryptionKeysForUser(new_password, user.email);\n\n var data = {};\n data.current_password = current_keys.pw;\n data.password = new_keys.pw;\n data.password_confirmation = new_keys.pw;\n\n var user = this.user;\n\n this._performPasswordChange(current_keys, new_keys, function(response){\n if(response && !response.errors) {\n // this.showNewPasswordForm = false;\n // reencrypt data with new gk\n this.reencryptAllItemsAndSave(user, new_keys.gk, current_keys.gk, function(success){\n if(success) {\n this.setGk(new_keys.gk);\n alert(\"Your password has been changed and your data re-encrypted.\");\n } else {\n // rollback password\n this._performPasswordChange(new_keys, current_keys, function(response){\n alert(\"There was an error changing your password. Your password has been rolled back.\");\n window.location.reload();\n })\n }\n }.bind(this));\n } else {\n // this.showNewPasswordForm = false;\n alert(\"There was an error changing your password. Please try again.\");\n }\n })\n }\n\n this._performPasswordChange = function(email, current_keys, new_keys, callback) {\n var request = Restangular.one(\"auth\");\n request.user = {password: new_keys.pw, password_confirmation: new_keys.pw, current_password: current_keys.pw, email: email};\n request.patch().then(function(response){\n callback(response);\n })\n }\n\n\n /*\n User\n */\n\n this.setUsername = function(user, username, callback) {\n var request = Restangular.one(\"users\", user.id).one(\"set_username\");\n request.username = username;\n request.post().then(function(response){\n callback(response.plain());\n })\n }\n\n /*\n Ensures that if encryption is disabled, all local items are uncrypted,\n and that if it's enabled, that all local items are encrypted\n */\n this.verifyEncryptionStatusOfAllItems = function(user, callback) {\n var allItems = user.filteredItems();\n var itemsNeedingUpdate = [];\n allItems.forEach(function(item){\n if(!item.isPublic()) {\n if(item.encryptionEnabled() && !item.isEncrypted()) {\n itemsNeedingUpdate.push(item);\n }\n } else {\n if(item.isEncrypted()) {\n itemsNeedingUpdate.push(item);\n }\n }\n }.bind(this))\n\n if(itemsNeedingUpdate.length > 0) {\n console.log(\"verifying encryption, items need updating\", itemsNeedingUpdate);\n this.saveBatchItems(user, itemsNeedingUpdate, callback)\n }\n }\n\n\n\n /*\n Items\n */\n\n this.saveDirtyItems = function(callback) {\n var dirtyItems = modelManager.dirtyItems;\n\n this.saveItems(dirtyItems, function(response){\n modelManager.clearDirtyItems();\n callback();\n })\n }\n\n this.saveItems = function(items, callback) {\n console.log(\"saving items\", items);\n var request = Restangular.one(\"users\", this.user.uuid).one(\"items\");\n request.items = _.map(items, function(item){\n return this.createRequestParamsForItem(item);\n }.bind(this));\n console.log(\"sending request items\", request.items);\n\n request.post().then(function(response) {\n var savedItems = response.items;\n console.log(\"response items\", savedItems);\n // items.forEach(function(item) {\n // _.merge(item, _.find(savedItems, {uuid: item.uuid}));\n // })\n callback(response);\n })\n }\n\n this.createRequestParamsForItem = function(item) {\n var itemCopy = _.cloneDeep(item);\n\n var params = {uuid: item.uuid, content_type: item.content_type};\n itemCopy.content.references = _.map(itemCopy.content.references, function(reference){\n return {uuid: reference.uuid, content_type: reference.content_type};\n })\n\n if(!item.isPublic()) {\n // encrypted\n this.encryptSingleItem(itemCopy, this.retrieveGk());\n params.content = itemCopy.content;\n params.loc_eek = itemCopy.loc_eek;\n }\n else {\n // decrypted\n params.content = JSON.stringify(item.content);\n params.loc_eek = null;\n }\n return params;\n }\n\n\n this.deleteItem = function(item, callback) {\n if(!this.user.id) {\n this.writeUserToLocalStorage(this.user);\n callback(true);\n } else {\n Restangular.one(\"users\", this.user.uuid).one(\"items\", item.uuid).remove()\n .then(function(response) {\n callback(true);\n })\n }\n }\n\n this.shareItem = function(item, callback) {\n if(!this.user.id) {\n alert(\"You must be signed in to share.\");\n } else {\n Restangular.one(\"users\", this.user.uuid).one(\"items\", item.uuid).one(\"presentations\").post()\n .then(function(response){\n var presentation = response.plain();\n _.merge(item, {presentation: presentation});\n callback(item);\n\n // decrypt references\n if(item.references.length > 0) {\n this.saveBatchItems(item.references, function(success){})\n }\n })\n }\n }\n\n this.unshareItem = function(item, callback) {\n var request = Restangular.one(\"users\", this.user.uuid).one(\"items\", item.uuid).one(\"presentations\", item.presentation.uuid);\n request.remove().then(function(response){\n item.presentation = null;\n callback(null);\n\n // encrypt references\n if(item.references.length > 0) {\n this.saveBatchItems(item.references, function(success){})\n }\n })\n }\n\n\n /*\n Presentations\n */\n\n this.updatePresentation = function(resource, presentation, callback) {\n var request = Restangular.one(\"users\", this.user.id)\n .one(\"items\", resource.id)\n .one(\"presentations\", resource.presentation.id);\n _.merge(request, presentation);\n request.patch().then(function(response){\n callback(response.plain());\n })\n .catch(function(error){\n callback(nil);\n })\n }\n\n\n /*\n Import\n */\n\n this.importJSONData = function(jsonString, callback) {\n var data = JSON.parse(jsonString);\n var user = new User(data);\n console.log(\"importing data\", JSON.parse(jsonString));\n user.items.forEach(function(item) {\n if(item.isPublic()) {\n item.setContentRaw(JSON.stringify(item.content));\n } else {\n this.encryptSingleItemWithLocalKey(item);\n }\n\n // prevent circular links\n item.tag = null;\n }.bind(this))\n\n user.tags.forEach(function(tag){\n // prevent circular links\n tag.items = null;\n })\n\n var request = Restangular.one(\"import\");\n request.data = {items: user.items, tags: user.tags};\n request.post().then(function(response){\n callback(true, response);\n })\n .catch(function(error){\n callback(false, error);\n })\n }\n\n /*\n Export\n */\n\n this.itemsDataFile = function(user) {\n var textFile = null;\n var makeTextFile = function (text) {\n var data = new Blob([text], {type: 'text/json'});\n\n // If we are replacing a previously generated file we need to\n // manually revoke the object URL to avoid memory leaks.\n if (textFile !== null) {\n window.URL.revokeObjectURL(textFile);\n }\n\n textFile = window.URL.createObjectURL(data);\n\n // returns a URL you can use as a href\n return textFile;\n }.bind(this);\n\n var presentationParams = function(presentation) {\n if(!presentation) {\n return null;\n }\n\n return {\n id: presentation.id,\n uuid: presentation.uuid,\n root_path: presentation.root_path,\n relative_path: presentation.relative_path,\n presentable_type: presentation.presentable_type,\n presentable_id: presentation.presentable_id,\n created_at: presentation.created_at,\n modified_at: presentation.modified_at,\n }\n }\n\n var items = _.map(user.filteredItems(), function(item){\n return {\n id: item.id,\n uuid: item.uuid,\n content: item.content,\n tag_id: item.tag_id,\n created_at: item.created_at,\n modified_at: item.modified_at,\n presentation: presentationParams(item.presentation)\n }\n });\n\n var tags = _.map(user.tags, function(tag){\n return {\n id: tag.id,\n uuid: tag.uuid,\n name: tag.name,\n created_at: tag.created_at,\n modified_at: tag.modified_at,\n presentation: presentationParams(tag.presentation)\n }\n });\n\n var data = {\n items: items,\n tags: tags\n }\n\n return makeTextFile(JSON.stringify(data, null, 2 /* pretty print */));\n }\n\n\n\n\n /*\n Merging\n */\n this.mergeLocalDataRemotely = function(user, callback) {\n var request = Restangular.one(\"users\", user.id).one(\"merge\");\n var tags = user.tags;\n request.items = user.items;\n request.items.forEach(function(item){\n if(item.tag_id) {\n var tag = tags.filter(function(tag){return tag.id == item.tag_id})[0];\n item.tag_name = tag.name;\n }\n })\n request.post().then(function(response){\n callback();\n localStorage.removeItem('user');\n })\n }\n\n\n\n\n\n\n this.staticifyObject = function(object) {\n return JSON.parse(JSON.stringify(object));\n }\n\n this.writeUserToLocalStorage = function(user) {\n var saveUser = _.cloneDeep(user);\n saveUser.items = Item.filterDummyItems(saveUser.items);\n saveUser.tags.forEach(function(tag){\n tag.items = null;\n }.bind(this))\n this.writeToLocalStorage('user', saveUser);\n }\n\n this.writeToLocalStorage = function(key, value) {\n localStorage.setItem(key, angular.toJson(value));\n }\n\n this.localUser = function() {\n var user = JSON.parse(localStorage.getItem('user'));\n if(!user) {\n user = {items: [], tags: []};\n }\n user.shouldMerge = true;\n return user;\n }\n\n /*\n Drafts\n */\n\n this.saveDraftToDisk = function(draft) {\n // localStorage.setItem(\"draft\", JSON.stringify(draft));\n }\n\n this.clearDraft = function() {\n localStorage.removeItem(\"draft\");\n }\n\n this.getDraft = function() {\n var draftString = localStorage.getItem(\"draft\");\n if(!draftString || draftString == 'undefined') {\n return null;\n }\n return new Item(JSON.parse(draftString));\n }\n\n\n /*\n Encrpytion\n */\n\n this.retrieveGk = function() {\n if(!this.gk) {\n this.gk = localStorage.getItem(\"gk\");\n }\n return this.gk;\n }\n\n this.setGk = function(gk) {\n localStorage.setItem('gk', gk);\n }\n\n this.signout = function() {\n localStorage.removeItem(\"jwt\");\n localStorage.removeItem(\"gk\");\n }\n\n this.encryptSingleItem = function(item, key) {\n var ek = null;\n if(item.loc_eek) {\n ek = Neeto.crypto.decryptText(item.loc_eek, key);\n } else {\n ek = Neeto.crypto.generateRandomEncryptionKey();\n item.loc_eek = Neeto.crypto.encryptText(ek, key);\n }\n item.content = Neeto.crypto.encryptText(JSON.stringify(item.content), ek);\n item.local_encryption_scheme = \"1.0\";\n }\n\n this.encryptItems = function(items, key) {\n items.forEach(function(item){\n this.encryptSingleItem(item, key);\n }.bind(this));\n }\n\n this.encryptSingleItemWithLocalKey = function(item) {\n this.encryptSingleItem(item, this.retrieveGk());\n }\n\n this.encryptItemsWithLocalKey = function(items) {\n this.encryptItems(items, this.retrieveGk());\n }\n\n this.encryptNonPublicItemsWithLocalKey = function(items) {\n var nonpublic = items.filter(function(item){\n return !item.isPublic() && !item.pending_share;\n })\n this.encryptItems(nonpublic, this.retrieveGk());\n }\n\n this.decryptSingleItemWithLocalKey = function(item) {\n this.decryptSingleItem(item, this.retrieveGk());\n }\n\n this.decryptSingleItem = function(item, key) {\n var ek = Neeto.crypto.decryptText(item.loc_eek || item.local_eek, key);\n var content = Neeto.crypto.decryptText(item.content, ek);\n // console.log(\"decrypted contnet\", content);\n item.content = content;\n }\n\n this.decryptItems = function(items, key) {\n items.forEach(function(item){\n // console.log(\"is encrypted?\", item);\n if(item.loc_eek && typeof item.content === 'string') {\n this.decryptSingleItem(item, key);\n }\n }.bind(this));\n }\n\n this.decryptItemsWithLocalKey = function(items) {\n this.decryptItems(items, this.retrieveGk());\n }\n\n this.reencryptAllItemsAndSave = function(user, newKey, oldKey, callback) {\n var items = user.filteredItems();\n items.forEach(function(item){\n if(item.loc_eek && typeof item.content === 'string') {\n // first decrypt eek with old key\n var ek = Neeto.crypto.decryptText(item.loc_eek, oldKey);\n // now encrypt ek with new key\n item.loc_eek = Neeto.crypto.encryptText(ek, newKey);\n }\n });\n\n this.saveBatchItems(user, items, function(success) {\n callback(success);\n }.bind(this));\n }\n }\n});\n;class ItemManager {\n\n set items(items) {\n this._items = items;\n this.resolveReferences();\n }\n\n get items() {\n return this._items;\n }\n\n referencesForItemId(itemId) {\n return _.find(this.items, {uuid: itemId});\n }\n\n resolveReferences() {\n this.items.forEach(function(item){\n // build out references\n item.content.references = _.map(item.content.references, function(reference){\n return this.referencesForItemId(reference.uuid);\n }.bind(this))\n }.bind(this));\n }\n\n itemsForContentType(contentType) {\n return this.items.filter(function(item){\n return item.content_type == contentType;\n });\n }\n\n // returns dirty item references that need saving\n deleteItem(item) {\n _.remove(this.items, item);\n item.content.references.forEach(function(referencedItem){\n this.removeReferencesBetweenItems(referencedItem, item);\n }.bind(this))\n\n return item.content.references;\n }\n\n removeReferencesBetweenItems(itemOne, itemTwo) {\n itemOne.removeReference(itemTwo);\n itemTwo.removeReference(itemOne);\n return [itemOne, itemTwo];\n }\n\n createReferencesBetweenItems(itemOne, itemTwo) {\n itemOne.addReference(itemTwo);\n itemTwo.addReference(itemOne);\n return [itemOne, itemTwo];\n }\n}\n\nangular.module('app.frontend').service('itemManager', ItemManager);\n;angular.module('app.frontend')\n .service('markdownRenderer', function ($sce) {\n\n marked.setOptions({\n breaks: true,\n sanitize: true\n });\n\n this.renderedContentForText = function(text) {\n if(!text || text.length == 0) {\n return \"\";\n }\n return marked(text);\n }\n\n this.renderHtml = function(html_code) {\n return $sce.trustAsHtml(html_code);\n };\n\n\n });\n;class ModelManager extends ItemManager {\n\n constructor() {\n super();\n this.notes = [];\n this.groups = [];\n this.dirtyItems = [];\n }\n\n set items(items) {\n super.items = items;\n this.notes = _.map(this.itemsForContentType(\"Note\"), function(json_obj) {\n return new Note(json_obj);\n })\n\n this.tags = _.map(this.itemsForContentType(\"Tag\"), function(json_obj) {\n var tag = new Tag(json_obj);\n console.log(\"tag references upon import\", tag.content.references);\n tag.updateReferencesLocalMapping();\n return tag;\n })\n }\n\n get items() {\n return super.items;\n }\n\n addDirtyItems(items) {\n if(!(items instanceof Array)) {\n items = [items];\n }\n\n this.dirtyItems = this.dirtyItems.concat(items);\n this.dirtyItems = _.uniq(this.dirtyItems);\n }\n\n get filteredNotes() {\n return Note.filterDummyNotes(this.notes);\n }\n\n clearDirtyItems() {\n this.dirtyItems = [];\n }\n\n addNote(note) {\n if(!_.find(this.notes, {uuid: note.uuid})) {\n this.notes.unshift(note);\n }\n }\n\n addTag(tag) {\n this.tags.unshift(tag);\n }\n\n addTagToNote(tag, note) {\n console.log(\"adding tag to note\", tag, note);\n var dirty = this.createReferencesBetweenItems(tag, note);\n this.refreshRelationshipsForTag(tag);\n this.refreshRelationshipsForNote(note);\n this.addDirtyItems(dirty);\n }\n\n refreshRelationshipsForTag(tag) {\n tag.notes = tag.referencesMatchingContentType(\"Note\");\n tag.notes.sort(function(a,b){\n return new Date(b.created_at) - new Date(a.created_at);\n });\n }\n\n refreshRelationshipsForNote(note) {\n note.tags = note.referencesMatchingContentType(\"Tag\");\n }\n\n removeTagFromNote(tag, note) {\n var dirty = this.removeReferencesBetweenItems(tag, note);\n this.addDirtyItems(dirty);\n }\n\n deleteNote(note) {\n var dirty = this.deleteItem(note);\n this.addDirtyItems(dirty);\n }\n\n deleteTag(tag) {\n var dirty = this.deleteItem(tag);\n this.addDirtyItems(dirty);\n }\n\n filteredNotes() {\n return Note.filterDummyNotes(this.notes);\n }\n}\n\nangular.module('app.frontend').service('modelManager', ModelManager);\n;angular.module('app.frontend')\n .service('serverSideValidation', function ($sce) {\n // Show validation errors in form.\n this.showErrors = function (formErrors, form) {\n angular.forEach(formErrors, function (errors, key) {\n if (typeof form[key] !== 'undefined') {\n form[key].$setDirty();\n form[key].$setValidity('server', false);\n form[key].$error.server = $sce.trustAsHtml(errors.join(', '));\n }\n });\n };\n\n // Get validation errors from server response and show them in form.\n this.parseErrors = function (response, form) {\n if (response.status === 422) {\n this.showErrors(response.data, form);\n }\n };\n});\n;angular\n .module('app.frontend')\n .directive('mbAutofocus', ['$timeout', function($timeout) {\n return {\n restrict: 'A',\n scope: {\n shouldFocus: \"=\"\n },\n link : function($scope, $element) {\n $timeout(function() {\n if($scope.shouldFocus) {\n $element[0].focus();\n }\n });\n }\n }\n }]);\n;angular\n .module('app.frontend')\n .directive('draggable', function() {\n return {\n scope: {\n note: \"=\"\n },\n link: function(scope, element) {\n // this gives us the native JS object\n var el = element[0];\n\n el.draggable = true;\n\n el.addEventListener(\n 'dragstart',\n function(e) {\n e.dataTransfer.effectAllowed = 'move';\n e.dataTransfer.setData('Note', JSON.stringify(scope.note));\n this.classList.add('drag');\n return false;\n },\n false\n );\n\n el.addEventListener(\n 'dragend',\n function(e) {\n this.classList.remove('drag');\n return false;\n },\n false\n );\n }\n }\n});\n\nangular\n .module('app.frontend')\n .directive('droppable', function() {\n return {\n scope: {\n drop: '&',\n bin: '=',\n tag: \"=\"\n },\n link: function(scope, element) {\n // again we need the native object\n var el = element[0];\n\n el.addEventListener(\n 'dragover',\n function(e) {\n e.dataTransfer.dropEffect = 'move';\n // allows us to drop\n if (e.preventDefault) e.preventDefault();\n this.classList.add('over');\n return false;\n },\n false\n );\n\n var counter = 0;\n\n el.addEventListener(\n 'dragenter',\n function(e) {\n counter++;\n this.classList.add('over');\n return false;\n },\n false\n );\n\n el.addEventListener(\n 'dragleave',\n function(e) {\n counter--;\n if (counter === 0) {\n this.classList.remove('over');\n }\n return false;\n },\n false\n );\n\n el.addEventListener(\n 'drop',\n function(e) {\n // Stops some browsers from redirecting.\n if (e.stopPropagation) e.stopPropagation();\n\n this.classList.remove('over');\n\n var binId = this.id;\n var note = new Note(JSON.parse(e.dataTransfer.getData('Note')));\n scope.$apply(function(scope) {\n var fn = scope.drop();\n if ('undefined' !== typeof fn) {\n fn(e, scope.tag, note);\n }\n });\n\n return false;\n },\n false\n );\n }\n }\n});\n;angular\n .module('app.frontend')\n .directive('fileChange', function() {\n return {\n restrict: 'A',\n scope: {\n handler: '&'\n },\n link: function (scope, element) {\n element.on('change', function (event) {\n scope.$apply(function(){\n scope.handler({files: event.target.files});\n });\n });\n }\n };\n});\n;angular\n .module('app.frontend')\n .directive('lowercase', function() {\n return {\n require: 'ngModel',\n link: function(scope, element, attrs, modelCtrl) {\n var lowercase = function(inputValue) {\n if (inputValue == undefined) inputValue = '';\n var lowercased = inputValue.toLowerCase();\n if (lowercased !== inputValue) {\n modelCtrl.$setViewValue(lowercased);\n modelCtrl.$render();\n }\n return lowercased;\n }\n modelCtrl.$parsers.push(lowercase);\n lowercase(scope[attrs.ngModel]);\n }\n };\n });\n;angular\n .module('app.frontend')\n .directive('selectOnClick', ['$window', function ($window) {\n return {\n restrict: 'A',\n link: function (scope, element, attrs) {\n element.on('focus', function () {\n if (!$window.getSelection().toString()) {\n // Required for mobile Safari\n this.setSelectionRange(0, this.value.length)\n }\n });\n }\n };\n}]);\n;angular\n .module('app.frontend')\n .directive('note', function($timeout) {\n return {\n restrict: 'E',\n controller: 'SingleNoteCtrl',\n templateUrl: \"frontend/directives/note.html\",\n scope: {\n note: \"=\"\n },\n }\n })\n .controller('SingleNoteCtrl', function ($rootScope, $scope, $state, markdownRenderer) {\n $scope.renderedContent = function() {\n return markdownRenderer.renderHtml(markdownRenderer.renderedContentForText($scope.note.text));\n }\n });\n;/**\n * AngularJS directive that simulates the effect of typing on a text editor - with a blinking cursor.\n * This directive works as an attribute to any HTML element, and it changes the speed/delay of its animation.\n *\n * There's also a simple less file included for basic styling of the dialog, which can be overridden.\n * The config object also lets the user define custom CSS classes for the modal.\n *\n * How to use:\n *\n * Just add the desired text to the 'text' attribute of the element and the directive takes care of the rest.\n * The 'text' attribute can be a single string or an array of string. In case an array is passed, the string\n * on each index is erased so the next item can be printed. When the last index is reached, that string stays\n * on the screen. (So if you want to erase the last string, just push an empty string to the end of the array)\n *\n * These are the optional preferences:\n * - initial delay: set an 'initial-delay' attribute for the element\n * - type delay: set a 'type-delay' attribute for the element\n * - erase delay: set a 'erase-delay' attribute for the element\n * - specify cursor : set a 'cursor' attribute for the element, specifying which cursor to use\n * - turn off cursor blinking: set the 'blink-cursor' attribute to \"false\"\n * - cursor blinking speed: set a 'blink-delay' attribute for the element\n * - scope callback: pass the desired scope callback as the 'callback-fn' attribute of the element\n *\n * Note:\n * Each time/delay value should be set either on seconds (1s) or milliseconds (1000)\n *\n * Dependencies:\n * The directive needs the css file provided in order to replicate the cursor blinking effect.\n */\n\n\nangular\n .module('app.frontend').directive('typewrite', ['$timeout', function ($timeout) {\n function linkFunction($scope, $element, $attrs) {\n var timer = null,\n initialDelay = $attrs.initialDelay ? getTypeDelay($attrs.initialDelay) : 200,\n typeDelay = $attrs.typeDelay || 200,\n eraseDelay = $attrs.eraseDelay || typeDelay / 2,\n blinkDelay = $attrs.blinkDelay ? getAnimationDelay($attrs.blinkDelay) : false,\n cursor = $attrs.cursor || '|',\n blinkCursor = typeof $attrs.blinkCursor !== 'undefined' ? $attrs.blinkCursor === 'true' : true,\n currentText,\n textArray,\n running,\n auxStyle;\n\n\n\n if ($scope.text) {\n if ($scope.text instanceof Array) {\n textArray = $scope.text;\n currentText = textArray[0];\n } else {\n currentText = $scope.text;\n }\n }\n if (typeof $scope.start === 'undefined' || $scope.start) {\n typewrite();\n }\n\n function typewrite() {\n timer = $timeout(function () {\n updateIt($element, 0, 0, currentText);\n }, initialDelay);\n }\n\n function updateIt(element, charIndex, arrIndex, text) {\n if (charIndex <= text.length) {\n updateValue(element, text.substring(0, charIndex) + cursor);\n charIndex++;\n timer = $timeout(function () {\n updateIt(element, charIndex, arrIndex, text);\n }, typeDelay);\n return;\n } else {\n charIndex--;\n\n if($scope.iterationCallback) {\n $scope.iterationCallback()(arrIndex);\n }\n\n // check if it's an array\n if (textArray && arrIndex < textArray.length - 1) {\n timer = $timeout(function () {\n cleanAndRestart(element, charIndex, arrIndex, textArray[arrIndex]);\n }, $scope.iterationDelay);\n } else {\n if ($scope.callbackFn) {\n $scope.callbackFn();\n }\n blinkIt(element, charIndex, currentText);\n }\n }\n }\n\n function blinkIt(element, charIndex) {\n var text = element.text().substring(0, element.text().length - 1);\n if (blinkCursor) {\n if (blinkDelay) {\n auxStyle = '-webkit-animation:blink-it steps(1) ' + blinkDelay + ' infinite;-moz-animation:blink-it steps(1) ' + blinkDelay + ' infinite ' +\n '-ms-animation:blink-it steps(1) ' + blinkDelay + ' infinite;-o-animation:blink-it steps(1) ' + blinkDelay + ' infinite; ' +\n 'animation:blink-it steps(1) ' + blinkDelay + ' infinite;';\n updateValue(element, text.substring(0, charIndex) + '' + cursor + '');\n } else {\n updateValue(element, text.substring(0, charIndex) + '' + cursor + '');\n }\n } else {\n updateValue(element, text.substring(0, charIndex));\n }\n }\n\n function cleanAndRestart(element, charIndex, arrIndex, currentText) {\n if(charIndex == 0) {\n if($scope.prebeginFn) {\n $scope.prebeginFn()();\n }\n }\n if (charIndex > 0) {\n currentText = currentText.slice(0, -1);\n // element.html(currentText.substring(0, currentText.length - 1) + cursor);\n updateValue(element, currentText + cursor);\n charIndex--;\n timer = $timeout(function () {\n cleanAndRestart(element, charIndex, arrIndex, currentText);\n }, eraseDelay);\n return;\n } else {\n arrIndex++;\n currentText = textArray[arrIndex];\n timer = $timeout(function () {\n updateIt(element, 0, arrIndex, currentText);\n }, typeDelay);\n }\n }\n\n function getTypeDelay(delay) {\n if (typeof delay === 'string') {\n return delay.charAt(delay.length - 1) === 's' ? parseInt(delay.substring(0, delay.length - 1), 10) * 1000 : +delay;\n } else {\n return false;\n }\n }\n\n function getAnimationDelay(delay) {\n if (typeof delay === 'string') {\n return delay.charAt(delay.length - 1) === 's' ? delay : parseInt(delay.substring(0, delay.length - 1), 10) / 1000;\n }\n }\n\n function updateValue(element, value) {\n if (element.prop('nodeName').toUpperCase() === 'INPUT') {\n return element.val(value);\n }\n return element.html(value);\n }\n\n $scope.$on('$destroy', function () {\n if (timer) {\n $timeout.cancel(timer);\n }\n });\n\n $scope.$watch('start', function (newVal) {\n if (!running && newVal) {\n running = !running;\n typewrite();\n }\n });\n\n $scope.$watch('text', function (newVal, oldVal) {\n if(!(newVal instanceof Array)) {\n currentText = newVal;\n typewrite();\n }\n });\n }\n\n return {\n restrict: 'A',\n link: linkFunction,\n replace: true,\n scope: {\n text: '=',\n callbackFn: '&',\n iterationCallback: '&',\n iterationDelay: '=',\n prebeginFn: '&',\n start: '='\n }\n };\n\n }]);\n;var Neeto = Neeto || {};\n\nNeeto.crypto = {\n\n generateRandomKey: function() {\n return CryptoJS.lib.WordArray.random(256/8).toString();\n },\n\n generateUUID: function() {\n var d = new Date().getTime();\n if(window.performance && typeof window.performance.now === \"function\"){\n d += performance.now(); //use high-precision timer if available\n }\n var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = (d + Math.random()*16)%16 | 0;\n d = Math.floor(d/16);\n return (c=='x' ? r : (r&0x3|0x8)).toString(16);\n });\n return uuid;\n },\n\n decryptText: function(encrypted_content, key) {\n return CryptoJS.AES.decrypt(encrypted_content, key).toString(CryptoJS.enc.Utf8);\n },\n\n encryptText: function(text, key) {\n return CryptoJS.AES.encrypt(text, key).toString();\n },\n\n generateRandomEncryptionKey: function() {\n var salt = Neeto.crypto.generateRandomKey();\n var passphrase = Neeto.crypto.generateRandomKey();\n return CryptoJS.PBKDF2(passphrase, salt, { keySize: 256/32 }).toString();\n },\n\n sha256: function(text) {\n return CryptoJS.SHA256(text).toString();\n },\n\n /** Generates two deterministic 256 bit keys based on one input */\n generateAsymmetricKeyPair: function(input, salt) {\n var output = CryptoJS.PBKDF2(input, salt, { keySize: 512/32, hasher: CryptoJS.algo.SHA512, iterations: 3000 });\n var firstHalf = _.clone(output);\n var secondHalf = _.clone(output);\n var sigBytes = output.sigBytes/2;\n var outputLength = output.words.length;\n firstHalf.words = output.words.slice(0, outputLength/2);\n secondHalf.words = output.words.slice(outputLength/2, outputLength);\n firstHalf.sigBytes = sigBytes;\n secondHalf.sigBytes = sigBytes;\n return [firstHalf.toString(), secondHalf.toString()];\n },\n\n generateEncryptionKeysForUser: function(password, email) {\n var keys = Neeto.crypto.generateAsymmetricKeyPair(password, email);\n var pw = keys[0];\n var gk = keys[1];\n\n return {pw: pw, gk: gk};\n }\n };\n"]} \ No newline at end of file