From 6ecd9224d775dc7ada0098c060e16f10299132f5 Mon Sep 17 00:00:00 2001 From: FoxUSA Date: Wed, 29 Nov 2017 21:43:07 -0700 Subject: [PATCH 01/17] Cleaned stuff up --- .jshintrc | 2 +- .project | 18 - .travis.yml | 6 +- Doc/Install.md | 6 - Gruntfile.js | 316 +++++++++--------- OpenNote.Test/unit/folder.js | 6 - OpenNote/bower.json | 22 -- OpenNote/index.html | 33 +- .../openNote/controllers/folderController.js | 9 +- .../openNote/controllers/noteController.js | 37 +- .../settings/databaseController.js | 4 +- .../controllers/settings/legacyController.js | 60 ---- .../openNote/controllers/tagListController.js | 2 + OpenNote/openNote/openNote.config.js | 37 -- OpenNote/openNote/openNote.js | 90 ++--- OpenNote/openNote/partials/folderPartial.html | 2 +- OpenNote/openNote/partials/navBarPartial.html | 11 +- OpenNote/openNote/partials/notePartial.html | 8 +- .../partials/settings/legacyPartial.html | 33 -- .../partials/settings/settingsPartial.html | 15 +- .../openNote/partials/tagListPartial.html | 3 +- OpenNote/openNote/router.js | 4 - .../openNote/services/legacyImportService.js | 80 ----- .../openNote/services/serverConfigService.js | 73 ---- OpenNote/openNote/services/userService.js | 164 --------- .../style/dark/ckeditor/moono.dark/dialog.css | 5 - .../dark/ckeditor/moono.dark/dialog_ie.css | 5 - .../dark/ckeditor/moono.dark/dialog_ie7.css | 5 - .../dark/ckeditor/moono.dark/dialog_ie8.css | 5 - .../ckeditor/moono.dark/dialog_iequirks.css | 5 - .../dark/ckeditor/moono.dark/dialog_opera.css | 5 - .../style/dark/ckeditor/moono.dark/editor.css | 5 - .../dark/ckeditor/moono.dark/editor_gecko.css | 5 - .../dark/ckeditor/moono.dark/editor_ie.css | 5 - .../dark/ckeditor/moono.dark/editor_ie7.css | 5 - .../dark/ckeditor/moono.dark/editor_ie8.css | 5 - .../ckeditor/moono.dark/editor_iequirks.css | 5 - .../style/dark/ckeditor/moono.dark/icons.png | Bin 23655 -> 0 bytes .../dark/ckeditor/moono.dark/images/arrow.png | Bin 261 -> 0 bytes .../dark/ckeditor/moono.dark/images/close.png | Bin 389 -> 0 bytes .../dark/ckeditor/moono.dark/images/mini.png | Bin 818 -> 0 bytes .../style/dark/ckeditor/moono.dark/readme.md | 51 --- OpenNote/openNote/style/invert/introjs.less | 128 ------- OpenNote/openNote/style/invert/note.less | 97 ------ OpenNote/openNote/style/invert/style.less | 2 +- OpenNote/package.json | 26 ++ _config.yml | 1 - package.json | 1 + 48 files changed, 267 insertions(+), 1140 deletions(-) delete mode 100644 .project delete mode 100644 OpenNote/bower.json delete mode 100644 OpenNote/openNote/controllers/settings/legacyController.js delete mode 100644 OpenNote/openNote/partials/settings/legacyPartial.html delete mode 100644 OpenNote/openNote/services/legacyImportService.js delete mode 100644 OpenNote/openNote/services/serverConfigService.js delete mode 100644 OpenNote/openNote/services/userService.js delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/dialog.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/dialog_ie.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/dialog_ie7.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/dialog_ie8.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/dialog_iequirks.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/dialog_opera.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/editor.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/editor_gecko.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/editor_ie.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/editor_ie7.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/editor_ie8.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/editor_iequirks.css delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/icons.png delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/images/arrow.png delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/images/close.png delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/images/mini.png delete mode 100644 OpenNote/openNote/style/dark/ckeditor/moono.dark/readme.md delete mode 100644 OpenNote/openNote/style/invert/introjs.less delete mode 100644 OpenNote/openNote/style/invert/note.less create mode 100644 OpenNote/package.json delete mode 100644 _config.yml diff --git a/.jshintrc b/.jshintrc index 0610a72..8fb55c3 100644 --- a/.jshintrc +++ b/.jshintrc @@ -8,6 +8,6 @@ "devel":true, "jquery":true, "jasmine": true, - "predef": [ "angular","alertify","", "PouchDB", "CKEDITOR","inject" ], + "predef": [ "angular","alertify","", "PouchDB","inject" ], "globals":{"openNote":true} } diff --git a/.project b/.project deleted file mode 100644 index 145bca8..0000000 --- a/.project +++ /dev/null @@ -1,18 +0,0 @@ - - - OpenNote - - - - - - tern.eclipse.ide.core.ternBuilder - - - - - - org.eclipse.angularjs.core.angularnature - tern.eclipse.ide.core.ternnature - - \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 6e53737..578f402 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: node_js node_js: - - '0.10' + - 0.10 before_script: - - 'npm install -g grunt-cli' - - + - npm install -g grunt-cli diff --git a/Doc/Install.md b/Doc/Install.md index 38b2da6..8836ee9 100644 --- a/Doc/Install.md +++ b/Doc/Install.md @@ -52,12 +52,6 @@ curl -X PUT http://127.0.0.1:5984/_config/ssl/key_file \ Now in `/OpenNote/#/settings/database/` put the following connection string in the `Replication url` field `https://admin:password@127.0.0.1:6984/opennote` -To import a database from older versions check out `/OpenNote/#/settings/legacy/` - -# Legacy service -The legacy service is still included to migrate data to the new data structure. -All write endpoints have been hidden with the exception of the file upload api's. - ### Automatic(Wizard Based Install) To run the installer open `/Service/install.php` diff --git a/Gruntfile.js b/Gruntfile.js index 9c76020..6855ada 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,162 +1,166 @@ module.exports = function(grunt) { - //Initializing the configuration object - grunt.initConfig({ - compress: { - main: { - options: { - archive: "build/version.zip" - }, - files: [{ - src: ["**/*"], - cwd:"OpenNote/", - expand: true - }] - } - }, - jshint: { - options:{ - }, - all: [ "**/*.js*",//Order matters - "!node_modules/**", - "!OpenNote/bower_components/**"] - }, - //Style - less: { - devDark: { - options: { - paths: ["assets/css"], - modifyVars: { - offset: "#000000" - } - }, - files: { - "OpenNote/openNote/style/invert/dark/style.css": "OpenNote/openNote/style/invert/style.less", - "OpenNote/openNote/style/invert/dark/note.css": "OpenNote/openNote/style/invert/note.less", - "OpenNote/openNote/style/invert/dark/alertify.css": "OpenNote/openNote/style/invert/alertify.less", - "OpenNote/openNote/style/invert/dark/intojs.css": "OpenNote/openNote/style/invert/introjs.less" - } - }, - devLight: { - options: { - paths: ["assets/css"], - modifyVars: { - offset: "#FFFFFF" - } - }, - files: { - "OpenNote/openNote/style/invert/light/style.css": "OpenNote/openNote/style/invert/style.less", - "OpenNote/openNote/style/invert/light/note.css": "OpenNote/openNote/style/invert/note.less", - "OpenNote/openNote/style/invert/light/alertify.css": "OpenNote/openNote/style/invert/alertify.less", - "OpenNote/openNote/style/invert/light/intojs.css": "OpenNote/openNote/style/invert/introjs.less" - } - }, - prodDark: { - options: { - paths: ["assets/css"], - cleancss: true, - modifyVars: { - offset: "#000000" - } - }, - files: { - "OpenNote/openNote/style/invert/dark/style.css": "OpenNote/openNote/style/invert/style.less", - "OpenNote/openNote/style/invert/dark/note.css": "OpenNote/openNote/style/invert/note.less", - "OpenNote/openNote/style/invert/dark/alertify.css": "OpenNote/openNote/style/invert/alertify.less", - "OpenNote/openNote/style/invert/dark/intojs.css": "OpenNote/openNote/style/invert/introjs.less" - } - }, - prodLight: { - options: { - paths: ["assets/css"], - cleancss: true, - modifyVars: { - offset: "#FFFFFF" - } - }, - files: { - "OpenNote/openNote/style/invert/light/style.css": "OpenNote/openNote/style/invert/style.less", - "OpenNote/openNote/style/invert/light/note.css": "OpenNote/openNote/style/invert/note.less", - "OpenNote/openNote/style/invert/light/alertify.css": "OpenNote/openNote/style/invert/alertify.less", - "OpenNote/openNote/style/invert/light/intojs.css": "OpenNote/openNote/style/invert/introjs.less" - } - } - }, - //Testing setup - karma: { - unit: { - configFile: "OpenNote.Test/karma.conf.js", - background: true - }, - travis: { - configFile: "OpenNote.Test/karma.conf.js", - singleRun: true, - browsers: ["PhantomJS"]//Override config browsers - } - }, - watch: { - karma: { - files: ["src/**/*.js", "test/unit/**/*.js"], - tasks: ["karma:unit:run"] - } - }, - shell: { - bowerInstall: { - command: [ "cd OpenNote", - "bower install" ].join("&&") - }, - clean:{ - command: [ "rm -rf build", - "cd OpenNote", - "rm -rf bower_components", - "cd openNote/style/invert/", - "rm -rf dark light"].join("&&") - } - }, - //HTML 5 - manifest: { - generate: { - options: { - basePath: "OpenNote/", - exclude: ["openNote.appcache", "Service", "bower_components/intro.js"], - verbose: true, - timestamp: true, - hash: true, - master: ["index.html"] - }, - src: [ - "**/*.js", - "**/*.css", - "**/*.html", - "**/*.png", - "**/*.jpg" - ], - dest: "OpenNote/openNote.appcache" - } - } - }); + //Initializing the configuration object + grunt.initConfig({ + compress: { + main: { + options: { + archive: "build/version.zip" + }, + files: [{ + src: ["**/*"], + cwd: "OpenNote/", + expand: true + }] + } + }, + connect: { + server: { + options: { + port: 8080, + base: "OpenNote", + keepalive:true + } + } + }, + jshint: { + options: {}, + all: ["**/*.js*", //Order matters + "!node_modules/**", + "!OpenNote/node_moduless/**" + ] + }, + //Style + less: { + devDark: { + options: { + paths: ["assets/css"], + modifyVars: { + offset: "#000000" + } + }, + files: { + "OpenNote/openNote/style/invert/dark/style.css": "OpenNote/openNote/style/invert/style.less", + "OpenNote/openNote/style/invert/dark/alertify.css": "OpenNote/openNote/style/invert/alertify.less" + } + }, + devLight: { + options: { + paths: ["assets/css"], + modifyVars: { + offset: "#FFFFFF" + } + }, + files: { + "OpenNote/openNote/style/invert/light/style.css": "OpenNote/openNote/style/invert/style.less", + "OpenNote/openNote/style/invert/light/alertify.css": "OpenNote/openNote/style/invert/alertify.less" + } + }, + prodDark: { + options: { + paths: ["assets/css"], + cleancss: true, + modifyVars: { + offset: "#000000" + } + }, + files: { + "OpenNote/openNote/style/invert/dark/style.css": "OpenNote/openNote/style/invert/style.less", + "OpenNote/openNote/style/invert/dark/alertify.css": "OpenNote/openNote/style/invert/alertify.less" + } + }, + prodLight: { + options: { + paths: ["assets/css"], + cleancss: true, + modifyVars: { + offset: "#FFFFFF" + } + }, + files: { + "OpenNote/openNote/style/invert/light/style.css": "OpenNote/openNote/style/invert/style.less", + "OpenNote/openNote/style/invert/light/alertify.css": "OpenNote/openNote/style/invert/alertify.less" + } + } + }, + //Testing setup + karma: { + unit: { + configFile: "OpenNote.Test/karma.conf.js", + background: true + }, + travis: { + configFile: "OpenNote.Test/karma.conf.js", + singleRun: true, + browsers: ["PhantomJS"] //Override config browsers + } + }, + watch: { + karma: { + files: ["src/**/*.js", "test/unit/**/*.js"], + tasks: ["karma:unit:run"] + } + }, + shell: { + npmInstall: { + command: ["cd OpenNote", + "npm install" + ].join("&&") + }, + clean: { + command: ["rm -rf build", + "cd OpenNote", + "rm -rf node_moduless", + "cd openNote/style/invert/", + "rm -rf dark light" + ].join("&&") + } + }, + //HTML 5 + manifest: { + generate: { + options: { + basePath: "OpenNote/", + exclude: ["openNote.appcache", "Service"], + verbose: true, + timestamp: true, + hash: true, + master: ["index.html"] + }, + src: [ + "**/*.js", + "**/*.css", + "**/*.html", + "**/*.png", + "**/*.jpg" + ], + dest: "OpenNote/openNote.appcache" + } + } + }); - //Plugin loading - grunt.loadNpmTasks("grunt-contrib-jshint"); - grunt.loadNpmTasks("grunt-contrib-less"); - grunt.loadNpmTasks("grunt-contrib-watch"); - grunt.loadNpmTasks("grunt-karma"); - grunt.loadNpmTasks("grunt-shell"); - grunt.loadNpmTasks("grunt-manifest"); - grunt.loadNpmTasks("grunt-contrib-compress"); + //Plugin loading + grunt.loadNpmTasks("grunt-contrib-jshint"); + grunt.loadNpmTasks("grunt-contrib-less"); + grunt.loadNpmTasks("grunt-contrib-watch"); + grunt.loadNpmTasks("grunt-karma"); + grunt.loadNpmTasks("grunt-shell"); + grunt.loadNpmTasks("grunt-manifest"); + grunt.loadNpmTasks("grunt-contrib-compress"); + grunt.loadNpmTasks("grunt-contrib-connect"); - //Task definition - //css - grunt.registerTask("buildDevCSS", ["less:devDark","less:devLight"]); - grunt.registerTask("buildProdCSS", ["less:prodDark","less:prodLight"]); + //Task definition + //css + grunt.registerTask("buildDevCSS", ["less:devDark", "less:devLight"]); + grunt.registerTask("buildProdCSS", ["less:prodDark", "less:prodLight"]); - //deployment - // you can run individual command using the plug-in command syntax suck as manifest:generate or shell:clean - grunt.registerTask("build", ["shell:bowerInstall", "buildDevCSS", "manifest:generate"]); - grunt.registerTask("default", ["build"]); - grunt.registerTask("deploy", ["shell:clean", "shell:bowerInstall", "buildProdCSS", "manifest:generate","compress"]); + //deployment + // you can run individual command using the plug-in command syntax suck as manifest:generate or shell:clean + grunt.registerTask("build", ["shell:npmInstall", "buildDevCSS", "manifest:generate"]); + grunt.registerTask("default", ["build", "connect:server"]); + grunt.registerTask("deploy", ["shell:clean", "shell:npmInstall", "buildProdCSS", "manifest:generate", "compress"]); - //testing - grunt.registerTask("devmode", ["karma:unit", "watch"]); - grunt.registerTask("test", ["karma:travis"]); - grunt.registerTask("ci", ["build","jshint:all","karma:travis"]); + //testing + grunt.registerTask("devmode", ["karma:unit", "watch"]); + grunt.registerTask("test", ["karma:travis"]); + grunt.registerTask("ci", ["build", "jshint:all", "karma:travis"]); }; diff --git a/OpenNote.Test/unit/folder.js b/OpenNote.Test/unit/folder.js index 2102929..3fc1205 100644 --- a/OpenNote.Test/unit/folder.js +++ b/OpenNote.Test/unit/folder.js @@ -23,12 +23,6 @@ describe("folderController", function() { $scope = $rootScope.$new(); this.$rootScope=$rootScope; - $rootScope.helpContent={ - newNoteButton: "", - newFolderButton: "", - findButton: "" - }; - $rootScope.buttons=[]; /** diff --git a/OpenNote/bower.json b/OpenNote/bower.json deleted file mode 100644 index 259584a..0000000 --- a/OpenNote/bower.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "opennote", - "authors": [ - "Jacob Liscom " - ], - "description": "A note taking software", - "version": "17.02.0", - "dependencies": { - "jquery": "2.1.4", - "bootstrap": "^3.3.6", - "angular": "^1.5.5", - "angular-route": "^1.5.5", - "angular-resource": "^1.5.5", - "angular-sanitize": "^1.5.5", - "angular-animate": "^1.5.5", - "angular-mocks": "^1.5.5", - "ckeditor": "ckeditor/ckeditor-releases#full/4.5.x", - "alertify": "0.3.10", - "intro.js": "0.8.0", - "pouchdb": "^5.3.2" - } -} diff --git a/OpenNote/index.html b/OpenNote/index.html index 539e1cb..44a4bda 100644 --- a/OpenNote/index.html +++ b/OpenNote/index.html @@ -1,5 +1,5 @@ - + @@ -16,31 +16,28 @@ - - + + - - - - + + + - - - - - + + + + + - - - + @@ -48,10 +45,7 @@ - - - @@ -66,7 +60,6 @@ - @@ -74,7 +67,7 @@
-
+
diff --git a/OpenNote/openNote/controllers/folderController.js b/OpenNote/openNote/controllers/folderController.js index 9bb79aa..835e948 100644 --- a/OpenNote/openNote/controllers/folderController.js +++ b/OpenNote/openNote/controllers/folderController.js @@ -20,8 +20,7 @@ openNote.controller("folderController", function( $scope, $scope.fadeOutFoldersAndNotes(function(){ $location.url("/note/").search("folderID",$scope.currentFolder._id); }); - }, - helpText: $rootScope.helpContent.newNoteButton + } }); //Create a folder @@ -47,8 +46,7 @@ openNote.controller("folderController", function( $scope, createFolder(folder); }, ""); - }, - helpText: $rootScope.helpContent.newFolderButton + } }); if($routeParams.id) @@ -76,8 +74,7 @@ openNote.controller("folderController", function( $scope, text: "Search", action: function(){ $location.url("/search/"+$scope.currentFolder.id); - }, - helpText: $rootScope.helpContent.findButton + } }); /** diff --git a/OpenNote/openNote/controllers/noteController.js b/OpenNote/openNote/controllers/noteController.js index c74c8a7..5fbc559 100644 --- a/OpenNote/openNote/controllers/noteController.js +++ b/OpenNote/openNote/controllers/noteController.js @@ -12,7 +12,6 @@ openNote.controller("noteController", function( $scope, $routeParams, storageService, config, - serverConfigService, $sce) { $rootScope.buttons=[]; $scope.note = {}; @@ -27,8 +26,7 @@ openNote.controller("noteController", function( $scope, text: "Save", action: function(){ save(); - }, - helpText: $rootScope.helpContent.saveButton + } }; }; @@ -50,8 +48,7 @@ openNote.controller("noteController", function( $scope, text: "Clear", action: function(){ $scope.clear(); - }, - helpText: $rootScope.helpContent.clearButton + } }; }; @@ -60,8 +57,7 @@ openNote.controller("noteController", function( $scope, text: "Edit", action: function(){ activateEditMode(); - }, - helpText: $rootScope.helpContent.editButton + } }; }; @@ -70,8 +66,7 @@ openNote.controller("noteController", function( $scope, text: "Go up a folder", action: function(){ $location.url("/folder/"+folderID); - }, - helpText: $rootScope.helpContent.editButton + } }; }; @@ -79,28 +74,28 @@ openNote.controller("noteController", function( $scope, * Take us into edit mode */ var activateEditMode = function(){ - serverConfigService.getEditorConfig().then(function(config){ - $scope.editMode=true; + //FIXME - if($scope.note._id) - $scope.showDeleteButton = true; + $scope.editMode=true; - CKEDITOR.replace("note", config); - $rootScope.buttons=[]; + if($scope.note._id) + $scope.showDeleteButton = true; - attachWindowUnload(); + $rootScope.buttons=[]; + + attachWindowUnload(); + + //Add new buttons + $rootScope.buttons.push(saveButton()); + $rootScope.buttons.push(clearButton()); - //Add new buttons - $rootScope.buttons.push(saveButton()); - $rootScope.buttons.push(clearButton()); - }); }; /** * Save a note */ var save = function(){ - $scope.note.note = CKEDITOR.instances.note.getData(); + //$scope.note.note = CKEDITOR.instances.note.getData();//FIXME $(".notePartial").fadeOut(config.fadeSpeedShort(),function(){ $scope.note.type="note"; diff --git a/OpenNote/openNote/controllers/settings/databaseController.js b/OpenNote/openNote/controllers/settings/databaseController.js index f629f0e..0a3d437 100644 --- a/OpenNote/openNote/controllers/settings/databaseController.js +++ b/OpenNote/openNote/controllers/settings/databaseController.js @@ -3,8 +3,7 @@ */ openNote.controller("databaseController", function( $scope, $rootScope, - storageService, - userService) { + storageService) { $scope.downloadFile = null; $scope.url = storageService.getRemoteURL(); @@ -38,7 +37,6 @@ openNote.controller("databaseController", function( $scope, return; storageService.destroyDatabase(function(){ - userService.destroyTokenHeader(); $rootScope.$emit("reloadListView", {}); window.location.href='#/'; $rootScope.$apply(); diff --git a/OpenNote/openNote/controllers/settings/legacyController.js b/OpenNote/openNote/controllers/settings/legacyController.js deleted file mode 100644 index a9eba69..0000000 --- a/OpenNote/openNote/controllers/settings/legacyController.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Search - */ -openNote.controller("legacyController", function( $scope, - $rootScope, - storageService, - userService, - config, - legacyImportService) { - - - $scope.username = userService.getUsername(); - $scope.password = ""; - $scope.url = config.servicePath(); - - /** - * Handle login - */ - $scope.login = function(){ - legacyImportService.setServiceURL($scope.url); - - userService.login($scope.username, $scope.password).then(function(data){ - if(data) - alertify.success("Credentials Accepted"); - else - alertify.error("Invalid credentials"); - }); - }; - - /** - * Handle register - */ - $scope.register = function(){ - legacyImportService.setServiceURL($scope.url); - - userService.register($scope.username, $scope.password).then(function(data){ - if(data) - alertify.success("Credentials Accepted"); - else - alertify.error("Invalid credentials"); - }); - }; - - /** - * Run legacy import - */ - $scope.import = function(){ - if(userService.hasValidToken()){ - legacyImportService.import(); - - //Wait until we are done and let the world know - $rootScope.$on("importComplete", function() { - alertify.success("Import has completed"); - $rootScope.$emit("reloadListView", {}); - }); - } - else - alertify.error("You must be logged in to run import"); - }; -}); diff --git a/OpenNote/openNote/controllers/tagListController.js b/OpenNote/openNote/controllers/tagListController.js index cf98f66..77d2ad4 100644 --- a/OpenNote/openNote/controllers/tagListController.js +++ b/OpenNote/openNote/controllers/tagListController.js @@ -20,6 +20,8 @@ openNote.controller("tagListController", function( $scope, $scope.tags.push(tag); $scope.$apply(); + }).catch(function(){ + //TODO }); }; diff --git a/OpenNote/openNote/openNote.config.js b/OpenNote/openNote/openNote.config.js index 75d44a1..1cc87f5 100644 --- a/OpenNote/openNote/openNote.config.js +++ b/OpenNote/openNote/openNote.config.js @@ -17,16 +17,6 @@ openNote.value("config", { return "https://cdn.rawgit.com/FoxUSA/OpenNote/master/package.json"; }, - /** - * http path to backend rest service - */ - servicePath: function(){ - var url = localStorage.getItem("serviceURL"); - if(url) - return url; - - return "./Service/service.php"; - }, /** * Used to compute random short fade speed @@ -42,33 +32,6 @@ openNote.value("config", { return 2000*Math.random()+200; }, - /** - * returns help contents - */ - getHelpContent: function(){ - return { - homeButton: "Click here to return to home page.", - listArea: "This area gives you a high level tree view of the folder structure. You can drag folder to re-arange them. To drag a folder into another, the parrent folder must be open.", - newNoteButton: "Allows you to create a new note in the the current folder.", - newFolderButton: "Allows you to create a sub folder in the current folder.", - findButton: "Launches the folder/note find utility.", - folderEditModeButton: "Click this button to reveal edit mode buttons. You cannot edit the Home folder.", - viewArea: "This is the main area. Folder browser and note editor are displayed here.", - noteBody: "This is the main note body. If edit mode is enabled this becomes the editor.", - clearButton: "Press this button to revert current changes.", - saveButton: "Click this to save this note. Old version are kept.", - editButton: "Click this to change the note into edit mode.", - noteTitle: "This the note title field. In edit mode, you can use it to edit the notes title." - }; - }, - - /** - * Do we want to show the help button - */ - showHelpButton: function(){ - return true; - }, - /** * See if we are dark or light */ diff --git a/OpenNote/openNote/openNote.js b/OpenNote/openNote/openNote.js index 6dc7539..1c94e5e 100644 --- a/OpenNote/openNote/openNote.js +++ b/OpenNote/openNote/openNote.js @@ -4,80 +4,44 @@ */ //Module Declaration -var openNote = angular.module("openNote", [ "ngRoute", - "ngResource", - "ngSanitize", - "ngAnimate"]); +var openNote = angular.module("openNote", ["ngRoute", + "ngResource", + "ngSanitize", + "ngAnimate" +]); /** * Used to redirect users to login if their token has expired * Runs on every route */ -openNote.run(function ( $rootScope, - $location, - userService, - config, - serverConfigService, - tagService, - $http){ +openNote.run(function($rootScope, + $location, + config, + tagService, + $http) { - $rootScope.helpContent=config.getHelpContent(); - $rootScope.version=config.getVersion(); + $rootScope.version = config.getVersion(); tagService.bindHandlers(); - $rootScope.$on("$routeChangeStart", function () { - //server config values - serverConfigService.getConfig().then(function(config){ - if(!config) - console.error("Connection to service failed"); - else - $rootScope.serverConfig=config; - }); //attach server config to root scope + $rootScope.$on("$routeChangeStart", function() { - //Initial entry after if logged in - if(!$rootScope.showMenu && !$rootScope.showSideBar)//make sure we only fade in/run once - $rootScope.$emit("init"); + //Initial entry after if logged in + if (!$rootScope.showMenu && !$rootScope.showSideBar) //make sure we only fade in/run once + $rootScope.$emit("init"); }); - /** - * Refresh token - */ - var tokenRefresh = function(){ - userService.login().then(function(response){ - if(response) - alertify.success("Token refreshed"); - else - alertify.error("Refreshed token failed"); - }).catch(function(){ - alertify.error("Refreshed token failed"); - }); - - }; - - /** * Initialize app and start fade in */ - $rootScope.$on("init",function(){ - userService.useAPITokenHeader();//use token - - $rootScope.showMenu=true; - $rootScope.showSideBar=true; - - //options for humans - $rootScope.showHelpButton = config.showHelpButton(); - - //Check for updates - $http.get(config.getUpdateURL()).then( - function(response){//Successful - if(response.data.version!=config.getVersion()) - alertify.log("Update available", "", 0); - } - ); - - //Setup auto login interval - if(userService.getUsername() && !$rootScope.autoLogInInterval){ - tokenRefresh(); - $rootScope.autoLogInInterval=setInterval(tokenRefresh, 1800000); - } - }); + $rootScope.$on("init", function() { + $rootScope.showMenu = true; + $rootScope.showSideBar = true; + + //Check for updates + $http.get(config.getUpdateURL()).then( + function(response) { //Successful + if (response.data.version != config.getVersion()) + alertify.log("Update available", "", 0); + } + ); + }); }); diff --git a/OpenNote/openNote/partials/folderPartial.html b/OpenNote/openNote/partials/folderPartial.html index c72c527..5430e69 100644 --- a/OpenNote/openNote/partials/folderPartial.html +++ b/OpenNote/openNote/partials/folderPartial.html @@ -4,7 +4,7 @@
  • {{parentFolder.name}}
  • -
  • +
  • {{currentFolder.name}}
  • diff --git a/OpenNote/openNote/partials/navBarPartial.html b/OpenNote/openNote/partials/navBarPartial.html index 2554874..deaa088 100644 --- a/OpenNote/openNote/partials/navBarPartial.html +++ b/OpenNote/openNote/partials/navBarPartial.html @@ -1,6 +1,6 @@ - diff --git a/OpenNote/openNote/partials/notePartial.html b/OpenNote/openNote/partials/notePartial.html index 78d9039..3886a26 100644 --- a/OpenNote/openNote/partials/notePartial.html +++ b/OpenNote/openNote/partials/notePartial.html @@ -1,11 +1,15 @@
    - +
    -
    + +
    + +
    diff --git a/OpenNote/openNote/partials/settings/legacyPartial.html b/OpenNote/openNote/partials/settings/legacyPartial.html deleted file mode 100644 index 8acaa38..0000000 --- a/OpenNote/openNote/partials/settings/legacyPartial.html +++ /dev/null @@ -1,33 +0,0 @@ -
    -
    File/Legacy Service
    - -
    \ No newline at end of file diff --git a/OpenNote/openNote/partials/settings/settingsPartial.html b/OpenNote/openNote/partials/settings/settingsPartial.html index 68e6e06..3bfff68 100644 --- a/OpenNote/openNote/partials/settings/settingsPartial.html +++ b/OpenNote/openNote/partials/settings/settingsPartial.html @@ -2,7 +2,7 @@
    Settings
    - +

    Database @@ -13,15 +13,4 @@

    - -
    -

    - File/Legacy API -

    -

    - Service used for uploading files and converting data from legacy service -

    -

    -

    -
    -
    \ No newline at end of file + diff --git a/OpenNote/openNote/partials/tagListPartial.html b/OpenNote/openNote/partials/tagListPartial.html index dacf686..857adbd 100644 --- a/OpenNote/openNote/partials/tagListPartial.html +++ b/OpenNote/openNote/partials/tagListPartial.html @@ -1,8 +1,7 @@ @@ -39,4 +39,9 @@

    Note

    + +
    +

    It looks like you dont have any folders. You can create one using the "New Folder" button in the top right of the page. If you need to pull your remote notes click here.

    +

    This folder is empty.

    +
    diff --git a/openNote/partials/navBarPartial.html b/openNote/partials/navBarPartial.html index deaa088..c60a252 100644 --- a/openNote/partials/navBarPartial.html +++ b/openNote/partials/navBarPartial.html @@ -11,10 +11,10 @@ diff --git a/openNote/style/invert/style.less b/openNote/style/invert/style.less index 46e2c6a..45bdc27 100644 --- a/openNote/style/invert/style.less +++ b/openNote/style/invert/style.less @@ -19,7 +19,7 @@ @treeHandleBackgroundColor: negation(#0b0908, @offset); @treeHandleBorderColor: negation(#231d17, @offset); - @copyRightColor: negation(#656565, @offset); + @copyRightColor: negation(#777777, @offset); @loginInputColor: negation(#444, @offset); body{ @@ -93,33 +93,6 @@ input:focus, select:focus, textarea:focus, button:focus { border-radius:4px;/*round the corners*/ } -#folderTitleBar{ - padding: 0px 0px 15px 0px; - overflow: hidden; - font-size: 18px; - - .breadcrumb{ - margin-bottom:0; - padding: 0 15px 0 0; - background: none; - float:left; - - >.active{ - color:inherit; - } - - li{ - font-size: 20px; - } - } -} - - #folderTitle{ - float:left; - padding-right:15px; - font-size: 20px; - } - .customButton{ /*custom button class that removes all browser formating*/ border: none; background:transparent; @@ -146,21 +119,6 @@ img { float: right; } -#sideBar{ - background: @navBackground; - - /*round the corners*/ - border-radius:4px ; - margin-bottom: 15px; - padding: 15px 15px 15px 30px; -} - -#sideBar ul{ - padding-left: 20px; -} - - - .box{ width: 250px; height: 150px; @@ -193,7 +151,7 @@ img { resize:none; /* copied from div.event */ - color: inherit; /*inherit from parrent*/ + color: inherit; /*inherit from parent*/ /*coped from body to prevent glitch*/ font-family: inherit; @@ -259,7 +217,7 @@ img { resize:none; /* copied from div.event */ - color: inherit; /*inherit from parrent*/ + color: inherit; /*inherit from parent*/ /*coped from body to prevent glitch*/ font-family: inherit; @@ -295,13 +253,68 @@ img { box-shadow: none; } - #copyRight{ - color: @copyRightColor; - padding-left: 50px; - } + + +// Main +#copyRight{ + color: @copyRightColor; + padding-left: 50px; +} + +#sideBar{ + background: @navBackground; + + /*round the corners*/ + border-radius:4px ; + margin-bottom: 15px; + padding: 15px 15px 15px 30px; +} + +#sideBar ul{ + padding-left: 20px; +} // Note partial -.notePartial .CodeMirror{ - border-radius:0 0 4px 4px;/*round the corners*/ - size: 75vh; +.notePartial{ + .CodeMirror{ + border-radius:0 0 4px 4px;/*round the corners*/ + size: 75vh; + } +} + + +// Folder partial +.folderPartial{ + #folderTitleBar{ + padding: 0px 0px 15px 0px; + overflow: hidden; + font-size: 18px; + + .breadcrumb{ + margin-bottom:0; + padding: 0 15px 0 0; + background: none; + float:left; + + >.active{ + color:inherit; + } + + li{ + font-size: 20px; + } + } + } + + #folderTitle{ + float:left; + padding-right:15px; + font-size: 20px; + } + + .noFolderHelp{ + margin-top: 25px; + text-align: center; + color: @copyRightColor + } } diff --git a/package.json b/package.json index 4dcef36..b4dcf48 100644 --- a/package.json +++ b/package.json @@ -34,12 +34,13 @@ "grunt-shell": "^0.7.0", "script-loader": "^0.7.2", "style-loader": "^0.19.0", + "testcafe": "^0.18.6", "url-loader": "^0.6.2", "webpack": "^3.8.1", "webpack-dev-server": "^2.9.5" }, "scripts": { - "test": "grunt ci", + "test": "testcafe chrome ./test/e2e/test.js -e -c 3", "dev": "webpack-dev-server --open --hot --config ./build/webpack.dev.config.js", "build": "webpack --progress --hide-modules --config ./build/webpack.prod.config.js" } diff --git a/test/e2e/test.js b/test/e2e/test.js new file mode 100644 index 0000000..faaec66 --- /dev/null +++ b/test/e2e/test.js @@ -0,0 +1,191 @@ +// jshint ignore: start + +import { Selector, ClientFunction } from "testcafe"; // first import testcafe selectors + +const WAIT_TIME = 500; // Time to wait after some actions to give angular time to re render + +fixture`Getting Started` + .page `http://127.0.0.1:8080/` + .afterEach(async testController => {//Clean up local storage and local db + let clean = ClientFunction(() => { + localStorage.clear(); + return PouchDB("openNote").destroy() + }); + + await clean(); + }); + +/** + * Create a folder. Expects to be in a folder partial. + * @param {[type]} testController [description] + * @param {[type]} name - name folder + * @return {testController} - testController object + */ +let createFolder = (testController, name) => { + return testController.click("#newFolder") + .typeText("#alertify-text", name) + .click("#alertify-ok"); +} + + +/** + * Create a note. Expects to be in a sub folder in a folder partial. + * @param {[type]} testController [description] + * @param {[type]} title [description] + * @param {[type]} note [description] + * @return {testController} - testController object + */ +let createNote = (testController, title, note) => { + let typeString = note.split("") + + typeString.forEach((char, index)=>{ + if(char != " ") + return; + typeString[index]="space"; + }); + typeString = typeString.join(" "); + + return testController.click("#newNote") + .typeText("#noteName", title,{replace:true}) + .click(".CodeMirror-scroll") + .pressKey(typeString) + .click("#save") +} + +/** + * Edits a note. Expects to be on a note partial + * @param {[type]} testController [description] + * @param {[type]} title [description] + * @param {[type]} note [description] + */ +let editNote = async (testController, title, note) => { + const CLEAR_STRING = "ctrl+a backspace" + let typeString = note.split("") + + typeString.forEach((char, index)=>{ + if(char != " ") + return; + typeString[index]="space"; + }); + typeString = typeString.join(" "); + + await testController.click("#edit") + .typeText("#noteName", title,{replace:true}) + .click(".CodeMirror-scroll") + .pressKey(CLEAR_STRING) + .pressKey(typeString) + .click("#save") +} + +test("Create Folder", async testController => { + //Arrange + + //Act + let folderName="TestFolder" + await createFolder(testController, folderName).wait(WAIT_TIME) + + //Asert + let result = await Selector("#currentFolder").innerText;//#Stupid should really just be sync + await testController.expect(result.trim()).eql(folderName); +}); + +test("Create note", async testController => { + //Arrange + + //Act + let title="TestNote"; + let tag = "#Something" + let note = `Now is the time for all good men to come to the aid of their country. ${tag}`; + + await createFolder(testController, "NoteTestFolder") + .wait(WAIT_TIME) + + await createNote(testController, title, note) + + //Asert + let titleActual = await Selector("#noteName").value; + let noteActual = await Selector("#note").innerText;//#Stupid should really just be sync + let tagActual = await Selector("#sideBar ul li:first-child ").innerText; + await testController.expect(titleActual).eql(title); + await testController.expect(noteActual.trim()).eql(note); + await testController.expect(tagActual).eql(tag.toLowerCase()); + +}); + +test("Edit note", async testController => { + //Arrange + + //Act + let title="TestNote"; + let tag = "#Something" + let note = `Now is the time for all good men to come to the aid of their country. ${tag}`; + + await createFolder(testController, "NoteTestFolder") + .wait(WAIT_TIME) + + await createNote(testController, title, note) + + title="TestNote2"; + tag = "#SomethingElse" + note = `YO ${tag}`; + + await editNote(testController, title, note) + + //Asert + let titleActual = await Selector("#noteName").value; + let noteActual = await Selector("#note").innerText;//#Stupid should really just be sync + let tagActual = await Selector("#sideBar ul li:first-child ").innerText; + await testController.expect(titleActual).eql(title); + await testController.expect(noteActual.trim()).eql(note); + await testController.expect(tagActual).eql(tag.toLowerCase()); +}); + +test("Delete note", async testController => { + //Arrange + + //Act + let folderName = "NoteTestFolder"; + await createFolder(testController, folderName) + .wait(WAIT_TIME); + + await createNote(testController, "TestNote", "Now is the time for all good men to come to the aid of their country. #something"); + + await testController.click("#edit") + .click("#removeNote") + .click("#alertify-ok"); + + //Asert + await testController.expect(Selector("#sideBar ul li:first-child ").innerText).eql("No tags found. Add a # to a note to add a tag."); + let result = await Selector("#currentFolder").innerText;//Make sure we are back to parent folder + await testController.expect(result.trim()).eql(folderName); +}); + +test("Delete folder tree", async testController => { + //Create first level + let firstLevelTag="#firstLevel" + await createFolder(testController, "NoteTestFolder") + .wait(WAIT_TIME) + await createNote(testController, "TestNote", `Quick. ${firstLevelTag}`).wait(WAIT_TIME); + await testController.expect(await Selector("#sideBar ul li:first-child ").innerText).eql(firstLevelTag.toLowerCase()); + + //Create second level + await testController.click("#goToParentFolder"); + await createFolder(testController, "SubFolder") + .wait(WAIT_TIME) + await createNote(testController, "Sub Note", "Bla #foo").wait(WAIT_TIME); + await testController.expect(Selector("#sideBar ul").childElementCount).eql(2);//We should have two tags + + //Delete it + await testController.click("#home") + .click(".folderPartial div.folder") + .click("#currentFolder") + .click("#delete") + .click("#alertify-ok") + .wait(WAIT_TIME); + + + await testController.expect(Selector("#sideBar ul li:first-child").innerText).eql("No tags found. Add a # to a note to add a tag."); //Make sure no tags + let result = await Selector("#currentFolder").innerText + await testController.expect(result.trim()).eql("Home");;//Make sure we are back to parent folder + await testController.expect(Selector(".folderPartial div.folder").length).eql(0);//Make sure there are no folders anymore +}); From 0324402d818bee64987262a7ddc16408fbfcc48b Mon Sep 17 00:00:00 2001 From: FoxUSA Date: Sat, 17 Feb 2018 00:31:54 -0700 Subject: [PATCH 12/17] Removed direct db call from controllers --- README.md | 41 +++++++---------------- docs/Upgrade.md | 4 +++ openNote/controllers/folderController.js | 10 +++--- openNote/controllers/noteController.js | 8 ++--- openNote/controllers/tagController.js | 3 +- openNote/controllers/tagListController.js | 2 +- 6 files changed, 28 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index bec1d1e..185b0b4 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -OpenNote [![Build Status](https://travis-ci.org/FoxUSA/OpenNote.png?branch=master)](https://travis-ci.org/FoxUSA/OpenNote) -============= +# OpenNote [![Build Status](https://travis-ci.org/FoxUSA/OpenNote.png?branch=master)](https://travis-ci.org/FoxUSA/OpenNote) + ![][responsive] -OpenNote was built to be a open source(MIT License), web based note taking software. -It is designed to be self hosted and gives you ownership of your data. +OpenNote is a progressive web application(PWA)/HTML5 offline app that was built to be a open source(MIT License), web based text editor/note taking software. +It is designed to be self hosted and gives you ownership of your data Please support this project by: - [Using GitTip][GitTip], @@ -25,9 +25,7 @@ https://foxusa.github.io/OpenNote/OpenNote/ Features -------- - BYOS(Bring Your Own Server) -- Full WYSIWYG editor - Touch friendly and mouse friendly ui -- Upload manager (not enabled in demo :) ) - Light weight - Multi user support - Search @@ -36,36 +34,25 @@ Features - Move Folders(Drag into another folder in the list view.) - Rename/Delete Folders(Click on folder title to get menu.) - Responsive - +- Tags +- [CLI](https://github.com/FoxUSA/OpenNote-CLI) Upcoming Features ----------------- -- Tags (You win) - Email to note -- Implement history viewer -- Install script -- Move Notes (Feature lost when migrating to Angular based list) - Mobile App Documentation ----------------- -[How to install][Install] - -[How to upgrade][Upgrade] - -[How to build](https://github.com/FoxUSA/OpenNote/blob/master/docs/Build.md) - -[Themes][Themes] - -[PHP backend][php] - +- [How to install][Install] +- [How to upgrade][Upgrade] +- [How to build](https://github.com/FoxUSA/OpenNote/blob/master/docs/Build.md) +-[Themes][Themes] -![][dark] License ------- JQuery - Distributed under the MIT License Angular - Distributed under the MIT License Bootstrap - Distributed under the MIT License - CKEditor - Distributed under the MPL License Angular UI Tree - Distributed under the MIT License Alertify.js - Distributed under the MIT License PouchDB - Distributed under the Apache License @@ -74,7 +61,7 @@ License OpenNote Code - Distributed under the MIT License - © Jacob Liscom 2017 + © Jacob Liscom 2018 Credits ------- @@ -82,13 +69,11 @@ Credits Kam Bnkamalesh - His TODO project heavily influenced my UI design -[topLevel]: https://raw.github.com/FoxUSA/OpenNote/master/docs/screenShots/topLevel.png -[dark]: https://raw.github.com/FoxUSA/OpenNote/master/docs/screenShots/dark1.png -[responsive]: https://raw.githubusercontent.com/FoxUSA/OpenNote/master/docs/screenShots/OpenNote.png +[topLevel]: ./docs/screenShots/topLevel.png +[responsive]: ./docs/screenShots/OpenNote.png [Install]: https://github.com/FoxUSA/OpenNote/blob/master/docs/Install.md [Upgrade]: https://github.com/FoxUSA/OpenNote/blob/master/docs/Upgrade.md -[PHP]: https://github.com/FoxUSA/OpenNoteService-PHP [Dependencies]: https://github.com/FoxUSA/OpenNote/blob/master/docs/Dependencies.md [Themes]: https://github.com/FoxUSA/OpenNote/blob/master/docs/Themes.md [GitTip]: https://www.gittip.com/FoxUSA/ diff --git a/docs/Upgrade.md b/docs/Upgrade.md index af1dadd..bcf82ac 100644 --- a/docs/Upgrade.md +++ b/docs/Upgrade.md @@ -1,5 +1,9 @@ # How to upgrade +//TODO + +If you have an issue with the html use https://domchristie.github.io/turndown/ to convert + ##Upgrading from 14.xx(Locomotive) to 15.07.01 All you need to do is merge your existing deployment with the release folder while keeping your config files (`openNote\openNote.config.js` and `\Service\Config.php`). Make sure to backup your old folder and database. diff --git a/openNote/controllers/folderController.js b/openNote/controllers/folderController.js index 8f5412b..c37ab75 100644 --- a/openNote/controllers/folderController.js +++ b/openNote/controllers/folderController.js @@ -100,7 +100,7 @@ openNote.controller("folderController", ["$scope", }; loadCurrentFolderContents(); } else { - storageService.database().get($routeParams.id).then(function(doc) { + storageService.get($routeParams.id).then(function(doc) { $scope.currentFolder = doc; loadCurrentFolderContents(); @@ -109,7 +109,7 @@ openNote.controller("folderController", ["$scope", name: "Home" }; else - storageService.database().get($scope.currentFolder.parentFolderID).then(function(doc) { + storageService.get($scope.currentFolder.parentFolderID).then(function(doc) { $scope.parentFolder = doc; $scope.$apply(); }); @@ -175,7 +175,7 @@ openNote.controller("folderController", ["$scope", return; $scope.currentFolder.name = data; - storageService.database().put($scope.currentFolder).then(function(result) { + storageService.put($scope.currentFolder).then(function(result) { $scope.currentFolder._rev = result.rev; $rootScope.$emit("reloadListView", {}); $scope.$apply(); @@ -227,7 +227,7 @@ openNote.controller("folderController", ["$scope", */ var createFolder = function(folder) { folder.type = "folder"; - storageService.database().post(folder).then(function(response) { + storageService.post(folder).then(function(response) { if (!response.ok) throw "//FIXME"; $rootScope.$emit("reloadListView", {}); @@ -243,7 +243,7 @@ openNote.controller("folderController", ["$scope", * Load the current folders contents */ var loadCurrentFolderContents = function() { - storageService.loadFolderContents($scope.currentFolder._id, function(results) { + storageService.loadFolderContents($scope.currentFolder._id).then(function(results) { $scope.currentFolderContents = results.rows; $scope.$apply(); diff --git a/openNote/controllers/noteController.js b/openNote/controllers/noteController.js index 8e08300..46723ec 100644 --- a/openNote/controllers/noteController.js +++ b/openNote/controllers/noteController.js @@ -149,11 +149,11 @@ openNote.controller("noteController", ["$scope", //Upsert if (!$scope.note._id) - storageService.database().post($scope.note).then(saveCallback, function() { + storageService.post($scope.note).then(saveCallback, function() { alertify.error("Error saving note"); }); else - storageService.database().put($scope.note).then(saveCallback, function() { + storageService.put($scope.note).then(saveCallback, function() { alertify.error("Error modifing note"); }); }); @@ -170,7 +170,7 @@ openNote.controller("noteController", ["$scope", var folderID = $scope.note.parentFolderID; //need to keep track of this because we are about to delete it $(".notePartial").fadeOut(config.fadeSpeedShort()); - storageService.database().remove($scope.note).then(function() { + storageService.delete($scope.note).then(function() { $rootScope.$emit("noteDeleted", $scope.note); detachWindowUnload(); alertify.success("Note Deleted"); //all done. close the notify dialog @@ -234,7 +234,7 @@ openNote.controller("noteController", ["$scope", /** * Load note */ - storageService.database().get($routeParams.id).then(function(doc) { + storageService.get($routeParams.id).then(function(doc) { $scope.note = doc; $scope.noteHTML = marked($scope.note.note); $(".notePartial").fadeIn(config.fadeSpeedLong()); diff --git a/openNote/controllers/tagController.js b/openNote/controllers/tagController.js index 2b15a54..bc85efa 100644 --- a/openNote/controllers/tagController.js +++ b/openNote/controllers/tagController.js @@ -32,9 +32,8 @@ openNote.controller("tagController", ["$scope", var loadTags = function() { tagService.getMap().then(function(map) { var tags = map.tags[$scope.tag]; - var db = storageService.database(); tags.forEach(function(tag) { - db.get(tag).then(function(note) { + storageService.get(tag).then(function(note) { $scope.notes.push(note); $scope.$apply(); }); diff --git a/openNote/controllers/tagListController.js b/openNote/controllers/tagListController.js index dbcf93a..2203a00 100644 --- a/openNote/controllers/tagListController.js +++ b/openNote/controllers/tagListController.js @@ -53,7 +53,7 @@ openNote.controller("tagListController", [ var origParentFolderID = request.moveObject.parentFolderID; request.moveObject.parentFolderID = request.destFolder._id; - storageService.database().put(request.moveObject).then(function() { + storageService.put(request.moveObject).then(function() { $rootScope.$emit("changedFolder", { //fire off an event to tell everyone we just modified a folder folder: request.moveObject, oldParentFolderID: origParentFolderID From 6001882555bf9100e39aa35c85ced0a05b5b7a9b Mon Sep 17 00:00:00 2001 From: FoxUSA Date: Sat, 24 Feb 2018 10:59:27 -0700 Subject: [PATCH 13/17] DRYed up folder logic for use in search. Use alldocs to greatly increase speed of search --- .travis.yml | 2 +- index.html | 3 +- openNote/controllers/folderController.js | 54 +-------- openNote/controllers/searchController.js | 103 +++++------------- openNote/directives/fadeOutDirective.js | 4 +- .../directives/folderContentsDirective.js | 68 ++++++++++++ .../directives/folderContentsPartial.html | 23 ++++ openNote/partials/folderPartial.html | 24 +--- openNote/partials/searchPartial.html | 43 +------- openNote/style/invert/style.less | 19 +++- 10 files changed, 140 insertions(+), 203 deletions(-) create mode 100644 openNote/directives/folderContentsDirective.js create mode 100644 openNote/partials/directives/folderContentsPartial.html diff --git a/.travis.yml b/.travis.yml index 578f402..967a59c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: node_js node_js: - - 0.10 + - node before_script: - npm install -g grunt-cli diff --git a/index.html b/index.html index ad776dc..a425934 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,6 @@ - + + diff --git a/openNote/controllers/folderController.js b/openNote/controllers/folderController.js index c37ab75..71dd085 100644 --- a/openNote/controllers/folderController.js +++ b/openNote/controllers/folderController.js @@ -84,7 +84,7 @@ openNote.controller("folderController", ["$scope", $rootScope.buttons.push({ text: "Search", action: function() { - $location.url("/search/" + $scope.currentFolder.id); + $location.url("/search/"); } }); @@ -125,45 +125,7 @@ openNote.controller("folderController", ["$scope", $scope.folderEditMode = !$scope.folderEditMode; }; - /** - * fade out all folders - */ - $scope.fadeOutFoldersAndNotes = function(callback) { - if ($scope.currentFolder.foldersInside || $scope.currentFolder.notesInside) { - $(".note").fadeTo(config.fadeSpeedShort(), 0, function() { - $scope.$apply(function() { - callback(); - }); - }); - $(".folder").fadeTo(config.fadeSpeedShort(), 0, function() { - $scope.$apply(function() { - callback(); - }); - }); - } else - callback(); - }; - - /** - * Load a folder - * @param folder- the folder to load - */ - $scope.loadFolder = function(folder) { - $scope.fadeOutFoldersAndNotes(function() { - $location.url("/folder/" + folder.doc._id); - }); - }; - - /** - * Load a note - * @param note - load a note - */ - $scope.loadNote = function(note) { - $scope.fadeOutFoldersAndNotes(function() { - $location.url("/note/" + note.id); - }); - }; /** * Rename the current folder @@ -250,20 +212,6 @@ openNote.controller("folderController", ["$scope", }); }; - /** - * Filter out everything but type folder - */ - $scope.folderFilter = function(object) { - return storageService.folderFilter(object); - }; - - /** - * Filter out everything but type note - */ - $scope.noteFilter = function(object) { - return storageService.noteFilter(object); - }; - //Load current folder $timeout($scope.loadCurrentFolder); } diff --git a/openNote/controllers/searchController.js b/openNote/controllers/searchController.js index f1e0f30..cf829b1 100644 --- a/openNote/controllers/searchController.js +++ b/openNote/controllers/searchController.js @@ -7,99 +7,46 @@ openNote.controller("searchController", ["$scope", "config", "storageService", "$location", + "$routeParams", + "$timeout", function($scope, $rootScope, config, storageService, - $location) { - /** - * Default valie - */ - $scope.searchRequest = { - type: "Both", - field: "Both", - search: "" - }; + $location, + $routeParams, + $timeout) { - $scope.notes = null; - $scope.folders = null; + $scope.searchString = $routeParams.id; //Default - /** - * Search the database - */ $scope.search = function() { + $location.url("/search/" + $scope.searchString); + }; + + $scope.loadResults = function() { + if (!$routeParams.id) + return; + alertify.log("Search started"); - $scope.notes = []; - $scope.folders = []; + $scope.results = []; - var removeDuplicates = function(array) { - var listOfIDs = []; - array.forEach(function(element) { //for each is synchronous - var index = listOfIDs.indexOf(element.id); - if (index == -1) { - listOfIDs.push(element.id); - } else - array.splice(index, 1); + storageService.allDocs().then(function(result) { + result.rows.filter(storageService.folderFilter).forEach(function(folder) { // search folders + if (folder.doc.name.match($routeParams.id)) //search folder name + return $scope.results.push(folder); }); - return array; - }; - var appendNotes = function(notes) { - $scope.notes = removeDuplicates($scope.notes.concat(notes)); - $scope.$apply(); - }; - - var appendFolders = function(folders) { - $scope.folders = $scope.folders.concat(folders); - alertify.success(folders.length + " objects found"); + result.rows.filter(storageService.noteFilter).forEach(function(note) { //Search notes + if (note.doc.title.match($routeParams.id) || note.doc.note.match($routeParams.id)) //search note name and title + return $scope.results.push(note); + }); $scope.$apply(); - }; - - var type = $scope.searchRequest.type; - var search = $scope.searchRequest.search; - var field = $scope.searchRequest.field; - - if (type == "Both" || type == "Folders") - storageService.searchFolderNames(search, appendFolders); - - if (type == "Both" || type == "Notes") { - if (field == "Both" || type == "Title") - storageService.searchNoteTitles(search, appendNotes); - - if (field == "Both" || type == "Body") - storageService.searchNoteBody(search, appendNotes); - } - }; - - /** - * Load a folder - * @param folder- the folder to load - */ - $scope.loadFolder = function(folder) { - $scope.fadeOutBoxes(function() { - $location.url("/folder/" + folder.doc._id); + alertify.success($scope.results.length + " objects found"); }); - }; - /** - * Load a note - * @param note - load a note - */ - $scope.loadNote = function(note) { - $scope.fadeOutBoxes(function() { - $location.url("/note/" + note.doc._id); - }); }; - /** - * fade out all boxes - */ - $scope.fadeOutBoxes = function(callback) { - $(".box").fadeOut(config.fadeSpeedShort(), function() { - $scope.$apply(function() { - callback(); - }); - }); - }; + //Load results + $timeout($scope.loadResults); } ]); diff --git a/openNote/directives/fadeOutDirective.js b/openNote/directives/fadeOutDirective.js index 67603ca..78fcc69 100644 --- a/openNote/directives/fadeOutDirective.js +++ b/openNote/directives/fadeOutDirective.js @@ -1,7 +1,5 @@ import openNote from "../openNote.js"; -/** - *randomly fade in element to have a wave effect - */ + openNote.directive("fadeOutDirective", function() { return { restrict: "C",//class diff --git a/openNote/directives/folderContentsDirective.js b/openNote/directives/folderContentsDirective.js new file mode 100644 index 0000000..1d514a8 --- /dev/null +++ b/openNote/directives/folderContentsDirective.js @@ -0,0 +1,68 @@ +import openNote from "../openNote.js"; + +openNote.directive("folderContentsDirective", [ + "config", + "storageService", + "$location", + function(config, storageService, $location) { + return { + restrict: "E", //class + templateUrl: "openNote/partials/directives/folderContentsPartial.html", + scope: { + fadeOut: "=", //basically make the fadeOut method public + contents: "<" //Accept contents as a parameter + }, + link: function($scope) { + /** + * fade out all folders + */ + $scope.fadeOut = function(callback) { + $(".note").fadeTo(config.fadeSpeedShort(), 0, function() { + $scope.$apply(function() { + callback(); + }); + }); + + $(".folder").fadeTo(config.fadeSpeedShort(), 0, function() { + $scope.$apply(function() { + callback(); + }); + }); + }; + + /** + * Load a folder + * @param folder- the folder to load + */ + $scope.loadFolder = function(folder) { //TODO DRY + $scope.fadeOut(function() { + $location.url("/folder/" + folder.doc._id); + }); + }; + + /** + * Load a note + * @param note - load a note + */ + $scope.loadNote = function(note) { //TODO DRY + $scope.fadeOut(function() { + $location.url("/note/" + note.id); + }); + }; + + /** + * Filter out everything but type folder + */ + $scope.folderFilter = function(object) { + return storageService.folderFilter(object); + }; + + /** + * Filter out everything but type note + */ + $scope.noteFilter = function(object) { + return storageService.noteFilter(object); + }; + } + }; + }]); diff --git a/openNote/partials/directives/folderContentsPartial.html b/openNote/partials/directives/folderContentsPartial.html new file mode 100644 index 0000000..6dac7fe --- /dev/null +++ b/openNote/partials/directives/folderContentsPartial.html @@ -0,0 +1,23 @@ +
    +

    + {{folder.doc.name}} +

    +

    +

    + Folder +

    +
    + +
    +

    + {{note.doc.title}} +

    +

    +

    + Note +

    +
    diff --git a/openNote/partials/folderPartial.html b/openNote/partials/folderPartial.html index 9dede3a..f2e71e6 100644 --- a/openNote/partials/folderPartial.html +++ b/openNote/partials/folderPartial.html @@ -16,29 +16,7 @@ -
    -

    - {{folder.doc.name}} -

    -

    -

    - Folder -

    -
    - -
    -

    - {{note.doc.title}} -

    -

    -

    - Note -

    -
    +

    It looks like you dont have any folders. You can create one using the "New Folder" button in the top right of the page. If you need to pull your remote notes click here.

    diff --git a/openNote/partials/searchPartial.html b/openNote/partials/searchPartial.html index 5024979..619d2f2 100644 --- a/openNote/partials/searchPartial.html +++ b/openNote/partials/searchPartial.html @@ -1,26 +1,9 @@
    -
    Search in Home
    +
    Search
    -
    -
    -

    - {{folder.doc.name}} -

    -

    -

    - Folder -

    -
    - -
    -

    - {{note.doc.title}} -

    -

    -

    - Note -

    -
    -
    + diff --git a/openNote/style/invert/style.less b/openNote/style/invert/style.less index 45bdc27..f8d8c4e 100644 --- a/openNote/style/invert/style.less +++ b/openNote/style/invert/style.less @@ -195,10 +195,6 @@ img { } } - .search, .search:hover, .search option{ - background-color: negation(@folderColor, #FFFFFF); - } - .searchPartial, .settingsPartials{ margin-bottom: 30px; @@ -274,6 +270,21 @@ img { padding-left: 20px; } +// Search +.searchPartial{ + + .search, + .search:hover, + .search option{ + background-color: negation(@folderColor, #FFFFFF); + } + + input::placeholder{ + color: @navBackground; + } + +} + // Note partial .notePartial{ .CodeMirror{ From a770ce62981eb089a49e57968c3301a8cdfaa8be Mon Sep 17 00:00:00 2001 From: FoxUSA Date: Sat, 24 Feb 2018 22:51:30 -0700 Subject: [PATCH 14/17] Release prep --- Changelog.md | 0 Gruntfile.js | 2 - README.md | 4 +- docs/Build.md | 38 +-- docs/History.md | 14 + docs/HowToUse.md | 78 ++++-- docs/Install.md | 138 +++------- docs/Upgrade.md | 33 ++- docs/{screenShots => images}/EditNote.png | Bin docs/{screenShots => images}/OpenNote.png | Bin docs/{screenShots => images}/OpenNoteHome.png | Bin docs/{screenShots => images}/ViewNote.png | Bin docs/{screenShots => images}/another view.png | Bin docs/{screenShots => images}/dark1.png | Bin docs/{screenShots => images}/dark2.png | Bin docs/{screenShots => images}/fullScreen.png | Bin docs/{screenShots => images}/plants.png | Bin docs/{screenShots => images}/seedsEdit.png | Bin docs/{screenShots => images}/seedsView.png | Bin docs/{screenShots => images}/topLevel.png | Bin docs/screenShots/login.png | Bin 11345 -> 0 bytes index.html | 3 +- openNote/controllers/folderController.js | 14 +- openNote/controllers/noteController.js | 8 +- openNote/controllers/searchController.js | 19 +- openNote/controllers/tagListController.js | 7 +- .../directives/folderContentsDirective.js | 14 +- package.json | 4 +- test/e2e/test.js | 251 ++++++------------ test/e2e/usecases/folder.create.test.js | 20 ++ test/e2e/usecases/folder.delete.test.js | 46 ++++ test/e2e/usecases/folder.deleteTree.test.js | 40 +++ test/e2e/usecases/note.create.test.js | 29 ++ test/e2e/usecases/note.delete.test.js | 28 ++ test/e2e/usecases/note.edit.test.js | 36 +++ test/karma.conf.js | 30 --- test/unit/folder.js | 62 ----- 37 files changed, 466 insertions(+), 452 deletions(-) create mode 100644 Changelog.md create mode 100644 docs/History.md rename docs/{screenShots => images}/EditNote.png (100%) rename docs/{screenShots => images}/OpenNote.png (100%) rename docs/{screenShots => images}/OpenNoteHome.png (100%) rename docs/{screenShots => images}/ViewNote.png (100%) rename docs/{screenShots => images}/another view.png (100%) rename docs/{screenShots => images}/dark1.png (100%) rename docs/{screenShots => images}/dark2.png (100%) rename docs/{screenShots => images}/fullScreen.png (100%) rename docs/{screenShots => images}/plants.png (100%) rename docs/{screenShots => images}/seedsEdit.png (100%) rename docs/{screenShots => images}/seedsView.png (100%) rename docs/{screenShots => images}/topLevel.png (100%) delete mode 100644 docs/screenShots/login.png create mode 100644 test/e2e/usecases/folder.create.test.js create mode 100644 test/e2e/usecases/folder.delete.test.js create mode 100644 test/e2e/usecases/folder.deleteTree.test.js create mode 100644 test/e2e/usecases/note.create.test.js create mode 100644 test/e2e/usecases/note.delete.test.js create mode 100644 test/e2e/usecases/note.edit.test.js delete mode 100644 test/karma.conf.js delete mode 100644 test/unit/folder.js diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..e69de29 diff --git a/Gruntfile.js b/Gruntfile.js index c1a5a5d..75242a1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -139,7 +139,6 @@ module.exports = function(grunt) { //Plugin loading grunt.loadNpmTasks("grunt-contrib-jshint"); grunt.loadNpmTasks("grunt-contrib-less"); - grunt.loadNpmTasks("grunt-contrib-watch"); grunt.loadNpmTasks("grunt-shell"); grunt.loadNpmTasks("grunt-manifest"); grunt.loadNpmTasks("grunt-contrib-compress"); @@ -159,6 +158,5 @@ module.exports = function(grunt) { grunt.registerTask("testDeploy", ["shell:clean", "buildProd", "connect:server"]); //testing - grunt.registerTask("devmode", ["karma:unit", "watch"]); grunt.registerTask("ci", "Build the app and runs tests on it", ["jshint:all", "buildProd", "connect:serverNoAlive", "shell:test" ]); }; diff --git a/README.md b/README.md index 185b0b4..9a77f45 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ Documentation - [How to install][Install] - [How to upgrade][Upgrade] - [How to build](https://github.com/FoxUSA/OpenNote/blob/master/docs/Build.md) --[Themes][Themes] +- [Themes][Themes] +- [Project history][History] License ------- @@ -73,6 +74,7 @@ Credits [responsive]: ./docs/screenShots/OpenNote.png [Install]: https://github.com/FoxUSA/OpenNote/blob/master/docs/Install.md +[History]: https://github.com/FoxUSA/OpenNote/blob/master/docs/History.md [Upgrade]: https://github.com/FoxUSA/OpenNote/blob/master/docs/Upgrade.md [Dependencies]: https://github.com/FoxUSA/OpenNote/blob/master/docs/Dependencies.md [Themes]: https://github.com/FoxUSA/OpenNote/blob/master/docs/Themes.md diff --git a/docs/Build.md b/docs/Build.md index 4f9ad37..cf2a84f 100644 --- a/docs/Build.md +++ b/docs/Build.md @@ -4,28 +4,36 @@ - Grunt `npm install -g grunt-cli` ## Build -Clone this project -`cd` into the project -Run `npm install` to fetch and install dependencies -Then run -`grunt build` -this will start a webpack dev server. +Clone [this project](https://github.com/FoxUSA/OpenNote) an the [SharedServices Project](https://github.com/FoxUSA/OpenNoteService-PHP) + +My project folder structure is setup as follows +``` +Some working folder +├─ OpenNote +├─ OpenNote-SharedServices +├─ OpenNote-Docer +└─ OpenNote-CLI +``` + -To test production bundles run `grunt testDeploy` +`cd` into the OpenNote +Run `npm install` to fetch and install dependencies +Then run`grunt` this will start a webpack dev server and open your browser. -//TODO new stuff and note in an ascii tree how the shared services are are expected to be neighbors of the cli and OpenNoteFolder +To test production bundles run `grunt testDeploy`. -//TODO grunt --help to get steps +### Usefull commands +You can see a full list of commands by running `grunt --help`. -Super important -grunt default or grunt -grunt ci -grunt deploy //TODO +Below are the most important commands +- `grunt default` or `grunt` to have webpack in development mode +- `grunt ci` run linting and tests +- `grunt deploy` Package up the project To develop tests ``` -grunt dev # in terminal A -npm run testChrome # in terminal B. Iterate on this terminal +grunt # in terminal A +npm run testSingle # in terminal B. Iterate on this terminal ``` diff --git a/docs/History.md b/docs/History.md new file mode 100644 index 0000000..93b69c0 --- /dev/null +++ b/docs/History.md @@ -0,0 +1,14 @@ +# OpenNote History + +Back in 2013 OneNote was started. Back then Microsoft OneNote did not have a full featured web interface. I used that at the time and had many notebooks. I wanted a way of taking those notes with me on my phone. I had limited data and wanted an application that would sync all my notes, let me modify them, and sync them back. I tried a bunch of applications and there were none that fulfilled my offline and tree structure requirements. + +## Open note +OpenNote has a text only design. No icons or symbols other than ascii non alphabetical characters. The application just so happened to end up this way. It has a very clean feel to it and does not distract you. I would like to keep this going forward +### Generation Alpha +The first version of OpenNote was a PHP fat application. Views were prepared by PHP and sent to the browser via a full load or AJAX. + +### Generation Beta +Second major revision was the switch to the then booming Angular 1 framework and use HTML5 application manifest and CouchDB to provided offline access and syncing. + +### Current Generation +The most recent efforts have been to add modern features. Tags, markdown, and a CLI. diff --git a/docs/HowToUse.md b/docs/HowToUse.md index ef4c4a1..0409429 100644 --- a/docs/HowToUse.md +++ b/docs/HowToUse.md @@ -1,34 +1,70 @@ -How to use --------------- -OpenNote uses a touch to open scheme. -If you want to open something just click it. +# How to use -## Login -To login simple go to your instance on OpenNote. You will need to have javascript enabled -Then simply click "Login" +``` ++---------+ +-------------------------+ +|OpenNote | | CouchDB | +|(Web App)+<--------------PouchDB sync----------------------->+//Stores notes and folder| ++----+----+ +--------------+----------+ + ^ ^ + | | + | |PouchDB sync + |Pre-signed urls | + | | + v v ++----+-------------------------+ +----------------------------+----------+ +|Minio | | OpenNote-CLI | +|//Stores blob data like images+<-S3 API (TEMP)-+//Allows use of other editors like Atom| ++------------------------------+ +---------------------------------------+ +``` -![][login] +OpenNote, when utilized fulloy, is made up of several components + +Component | Purpose +--------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +OpenNote | A PWA(Offline compatible) web application that allows you edit and access notes. +CouchDB | Couch DB is a database that stores your notes. When this is setup, you do not need to worry if your phone gets lost. When fully replicated, your notes will be safely stored in CouchDB. CouchDB also allows multiple browsers to sync. So you can have your notes on all your devices. +Minio | Minio is a blob storage server that implements the AWS S3 API. This allows you to upload your images and non text files for use with OpenNote/ +[OpenNote-CLI](https://github.com/FoxUSA/OpenNote-CLI) | OpenNote CLI syncs the database to disk. This allows you to use other editors like Atom to create and edit notes. + +## General + +OpenNote uses a touch to open scheme. If you want to open something just click it. ## Browsing -Now that you are logged in, you can browse around. At first you won't have any folders or notes. So, create some! -Once you have some stuff simply click on a folder(Always Green) or browse a tree view on the left to crawl into you notes. -![][topLevel] -Eventually you'll find a note(Always blue) that you want to open. Simply click it or touch it. +Now that you are logged in, you can browse around. At first you won't have any folders or notes. So, create some! Once you have some stuff simply click on a folder(Always Green) or browse a tree view on the left to crawl into you notes. + +![][toplevel] Eventually you'll find a note(Always blue) that you want to open. Simply click it or touch it. ![][plants] ## Notes + Once you click on a note you'll will be presented with it in a read only view. -![][seedsView] -If you want to edit a note, click on the "Edit" button in the top bar +![][seedsview] If you want to edit a note, click on the "Edit" button in the top bar + +![][seedsedit] This will bring you to the editor. Once you are all done editing, click "Save" to store the note. + +## Syncing +By default OpenNote is storing info in your browser. Until you setup syncing, you are at risk of lousing your notes. To setup syncing. From the home page click `Settings`, then click database. On the right hand side of the panel you will see a Replication url field. This expect a url to your couchDB database in the form of `$protocol://$user:$password@$serverurl:$port/$database`. + +For example if your server information is as follows: + +Item | Value +--- | --- +protocol | http +user | admin +password | password +serverurl | 127.0.0.1 +port | 6984 +database | opennote + +then your replication url would be `http://admin:password@127.0.0.1:6984/opennote` -![][seedsEdit] -This will bring you to the CKEditor. Once you are all done editing, click "Save" to store the note. +You will see an alert if replication is working. -[login]: https://raw.github.com/FoxUSA/OpenNote/master/Doc/screenShots/login.png -[topLevel]: https://raw.github.com/FoxUSA/OpenNote/master/Doc/screenShots/topLevel.png -[plants]: https://raw.github.com/FoxUSA/OpenNote/master/Doc/screenShots/plants.png -[seedsView]: https://raw.github.com/FoxUSA/OpenNote/master/Doc/screenShots/seedsView.png -[seedsEdit]: https://raw.github.com/FoxUSA/OpenNote/master/Doc/screenShots/seedsEdit.png +[plants]: ./images/plants.png +[seedsedit]: ./images/seedsEdit.png +[seedsview]: ./images/seedsView.png +[toplevel]: ./images/topLevel.png diff --git a/docs/Install.md b/docs/Install.md index 8836ee9..4d8d1bf 100644 --- a/docs/Install.md +++ b/docs/Install.md @@ -1,116 +1,38 @@ # How To Install -[Download most resent release from here.][Download] - -# HTML5 based new super fancy version -## Web app -Just extract in a HTML5 compatible webserver public directory. Or just use the [GitHub hosted version](https://foxusa.github.io/OpenNote/OpenNote/). - -## CouchDB Install -If you want sync your notes with a server, you will need to install CouchDB. -[CouchDB Download page](http://couchdb.apache.org/) - -You will need to enable CORS in CouchDB -The easiest way to do this is to use `add-cors-to-couchdb` -```shell -npm install -g add-cors-to-couchdb -add-cors-to-couchdb +Put the following text in a `docker-compose.yml`. Make sure to set all the items marked `#TODO`. Also make sure this file is in a secure place. Your credentials are stored in it. ``` +version: "2" +services: + opennote: + image: foxusa/opennote + ports: + - "8080:80" + couchdb: + image: couchdb + ports: + - "5984:5984" + - "6984:6984" + environment: + COUCHDB_USER: user #TODO set this + COUCHDB_PASSWORD: password #TODO set this + + minio: + image: minio/minio + volumes: + - "/tmp/data:/data" #TODO set this + ports: + - "9000:9000" + environment: + MINIO_ACCESS_KEY: tests #TODO set this + MINIO_SECRET_KEY: testssdfasdf #TODO set this + command: server /data -Run the commands below substituting `http://127.0.0.1:5984/` with the url of your server -```shell -# Create DB -curl -X PUT http://127.0.0.1:5984/opennote - -# Set permissions on opennote database -curl -X PUT http://localhost:5984/opennote/_security \ - -u admin:password \ - -H "Content-Type: application/json" \ - -d '{"admins": { "names": ["admin"], "roles": [] }, "members": { "names": ["admin"], "roles": [] } }' - -# SSL -curl -X PUT http://localhost:5984/_config/daemons/httpsd \ - -u admin:password \ - -H "Content-Type: application/json" \ - -d '"{couch_httpd, start_link, [https]}"' - -mkdir /etc/couchdb/cert -openssl genrsa > /etc/couchdb/cert/privkey.pem -openssl req -new -x509 -key /etc/couchdb/cert/privkey.pem -out /etc/couchdb/cert/mycert.pem -days 1095 - -curl -X PUT http://127.0.0.1:5984/_config/ssl/cert_file \ - -u admin:password \ - -H "Content-Type: application/json" \ - -d '"/etc/couchdb/cert/mycert.pem"' - -curl -X PUT http://127.0.0.1:5984/_config/ssl/key_file \ - -u admin:password \ - -H "Content-Type: application/json" \ - -d '"/etc/couchdb/cert/privkey.pem"' - -# Default SSL port 6984 -``` - -Now in `/OpenNote/#/settings/database/` put the following connection string in the `Replication url` field `https://admin:password@127.0.0.1:6984/opennote` - -### Automatic(Wizard Based Install) -To run the installer open -`/Service/install.php` - -Make sure you delete `install.php` and `Config.template`. - -#### Security Note -Be default we put the sqlite databse in the web folder. This is not a good idea. We solved this by putting in a htaccess file to not allow the database to be downloaded. - -Still, you should move this file out of the webserver directory and change the location in `Config.php` - -### Using Docker(Full Stack) -Make sure docker in running in daemon mode with restart previously running containers on -`docker -d -r` or you could louse your notes if you do not know what your doing - -Pull the current docker image -`docker pull foxusa/opennote` - -and run it on port 80 -`sudo docker run -d -p 80:80 -p 443:443 foxusa/opennote` - -or if port 80 is in use -`sudo docker run -d -p 8080:80 -p 8443:443 foxusa/opennote` - -### Manual -####MYSql -- Create a MYSQL database named "OpenNote" -- Download and extract OpenNote into a folder on your php web-server called "OpenNote" -- Open up the `Service/model/sql` folder and run `notebook.sql` in your OpenNote database -- Change the database connection settings inside of `Service/Config.php` to match your db settings. -These are stored in the following lines of code in `/OpenNote/Config.php`: -```php - $dbUserName = "notebook"; - $dbPassword = "password"; - $dbServer = "127.0.0.1"; - $dbName = "notebook"; ``` +## Start +`docker-compose up -d` to start -- Now the site install is complete. You can now open the site by going to your webserver url +/OpenNote -####SQLite -- Download and extract OpenNote into a folder on your php web-server called "OpenNote" -- Create a SQLite database file and execute the SQL DDL from `Service/model/sql` and run `notebook.sqlite.sql`. -- Change the database connection settings inside of `Service/Config.php` to match your db settings. -- These are stored in the following lines of code in `/OpenNote/Config.php`: -- Also make sure you have php5-sqlite driver installed and have group write access to SQLite database file, or you cannot register or login and you can't see any useful error messages. - -Uncomment the following lines in the dbConfig function: - -`return self::sqliteConfig()` - -Comment the following lines in the dbConfig function: - -`//return self::mysqlConfig();` - -```php - $dbName = "..//OpenNote.sqlite"; -``` -- Now the site install is complete. You can now open the site by going to your webserver url +/OpenNote -[Download]: https://github.com/FoxUSA/OpenNote/releases +## Uninstall +If you ever want to shutdown OpenNote run `docker-compose down` in the same folder as `docker-compose.yml`. This will shut down the containers associated with OpenNote. diff --git a/docs/Upgrade.md b/docs/Upgrade.md index bcf82ac..a04bcf9 100644 --- a/docs/Upgrade.md +++ b/docs/Upgrade.md @@ -1,10 +1,27 @@ # How to upgrade -//TODO +## Upgrading from 17.xx to 18.xx +There are major changes in this release. Make sure your data is backed up. +Launch new instance of OpenNote via the [install instructions](./Install.md). Then simply change your replication url to the new replication url and your notes will sync across. -If you have an issue with the html use https://domchristie.github.io/turndown/ to convert +In 18.xx the editor is mark down. If you have an issue with the HTML use https://domchristie.github.io/turndown/ to convert the text into markdown. -##Upgrading from 14.xx(Locomotive) to 15.07.01 + +The `upgrade` command included in [OpenNote-CLI](https://github.com/FoxUSA/OpenNote-CLI) version 18.03 will allow you to migrate all your files to the Minio instance launched by compose. It will also change all the links and pre-sign them for you. + +Sample command +``` +node index.js upgrade --jsonPath ../uploads.json \ + --legacyServiceUrl https://example \ + --s3Url http://127.0.0.1:9000 \ + --bucket opennote \ + --accessKey tests \ + --secretKey testssdfasdf +``` + +Only thing you will need is to dump the uploads table from the mysql legacy service and provide the path to it via the `--jsonPath` option. + +## Upgrading from 14.xx(Locomotive) to 15.07.01 All you need to do is merge your existing deployment with the release folder while keeping your config files (`openNote\openNote.config.js` and `\Service\Config.php`). Make sure to backup your old folder and database. @@ -12,7 +29,7 @@ There have been major changes in this release. You will need to follow the CouchDB instructions in the Install documentation. -##Docker(14.07.01 to 14.07.02) +## Docker(14.07.01 to 14.07.02) Find the container id of your running container by doing a `docker ps` or `docker ps -l` if the OpenNote conatiner was the last one you stopped. You should see output like this ``` @@ -61,16 +78,16 @@ or if port 80 is in use All done -##Manual installs +## Manual installs -##Upgrading from 14.07(Locomotive) to 14.07.01(Steam Locomotive) or 14.07.01(Steam Locomotive) to 14.07.02 (Diesel Locomotive). +## Upgrading from 14.07(Locomotive) to 14.07.01(Steam Locomotive) or 14.07.01(Steam Locomotive) to 14.07.02 (Diesel Locomotive). All you need to do is merge your existing deployment with the release folder while keeping your config files (`openNote\openNote.config.js` and `\Service\Config.php`). -###MySQL(Recomended) +### MySQL(Recomended) - Make sure you make a copy of you database and the OpenNote directory - Run `Service/model/sql/updateScripts/` scripts to roll the database up to current specs. - You will copy need to copy the upload directory contents into the new upload direcory in `Service/upload`. - You will also need to put int you database information in the new config `Service/Config.php` -###SQLite +### SQLite Same as the MySQL. You may need to slightly modify the sql upload script to be compatible with SQLite. I have included as much as I can in scripts with the postfix of .sqlite.sql. SQLite does not fully support the ALTER statement. diff --git a/docs/screenShots/EditNote.png b/docs/images/EditNote.png similarity index 100% rename from docs/screenShots/EditNote.png rename to docs/images/EditNote.png diff --git a/docs/screenShots/OpenNote.png b/docs/images/OpenNote.png similarity index 100% rename from docs/screenShots/OpenNote.png rename to docs/images/OpenNote.png diff --git a/docs/screenShots/OpenNoteHome.png b/docs/images/OpenNoteHome.png similarity index 100% rename from docs/screenShots/OpenNoteHome.png rename to docs/images/OpenNoteHome.png diff --git a/docs/screenShots/ViewNote.png b/docs/images/ViewNote.png similarity index 100% rename from docs/screenShots/ViewNote.png rename to docs/images/ViewNote.png diff --git a/docs/screenShots/another view.png b/docs/images/another view.png similarity index 100% rename from docs/screenShots/another view.png rename to docs/images/another view.png diff --git a/docs/screenShots/dark1.png b/docs/images/dark1.png similarity index 100% rename from docs/screenShots/dark1.png rename to docs/images/dark1.png diff --git a/docs/screenShots/dark2.png b/docs/images/dark2.png similarity index 100% rename from docs/screenShots/dark2.png rename to docs/images/dark2.png diff --git a/docs/screenShots/fullScreen.png b/docs/images/fullScreen.png similarity index 100% rename from docs/screenShots/fullScreen.png rename to docs/images/fullScreen.png diff --git a/docs/screenShots/plants.png b/docs/images/plants.png similarity index 100% rename from docs/screenShots/plants.png rename to docs/images/plants.png diff --git a/docs/screenShots/seedsEdit.png b/docs/images/seedsEdit.png similarity index 100% rename from docs/screenShots/seedsEdit.png rename to docs/images/seedsEdit.png diff --git a/docs/screenShots/seedsView.png b/docs/images/seedsView.png similarity index 100% rename from docs/screenShots/seedsView.png rename to docs/images/seedsView.png diff --git a/docs/screenShots/topLevel.png b/docs/images/topLevel.png similarity index 100% rename from docs/screenShots/topLevel.png rename to docs/images/topLevel.png diff --git a/docs/screenShots/login.png b/docs/screenShots/login.png deleted file mode 100644 index 0a3e90649cb1920c68d7e7b81fc9b3ed7a19aad0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11345 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%0D?)qZD5dtX9#*-l^ zHAe9Y>nqdIy3qC%+D`Z)P{w6@@&hh10;v8~_`t5&@hgOcgFCx#f1py#9FdyGeq#lK zq=4HWF+Ts{j+-{Pf5TpUV6TZjxcXW}jYJs(nKKbrw^H$+zQ)9_n(;*aA zDU!N}STlek(eh&}=xMaAuQ=d6l9_cj^w{bWIM?!jBHr1FfhZ;z<>gn4-uAY5gY@I7{$49%T`$w`_-U=lS&Hu>pxKOu-@s$FjGb zl{8m}HGSf`%soH6HM{xZwKtmRp^1jz~xPk z&l?X?>J41^&W-)hLu2VYj!(C?5Gf$_r6+kdX=U#_SvW0?widT7{6f~`xE-QRNrBmB zXv7o{{2z)z{7x}O6^f=yE^mf^EcZ&l3yz(q(} zGxdyADa^mDDhf>0r_cX)8B~gWCLK+@&AxC`SG}d9EKqDg{5?kHOG#lbVRXDSbKi}D zQHMe35bBYYY%ta|((r0wYo^P6KeG7#Q8llR=Nrf7aHDyObY3r3=WNPN@RFofam=w9IQI93&dL~z^&?Nvt@qHt*9 ziFCo%9PQnKTmFtLdGEOoGDU1OF*kQglM%j^O&sERq6_VnYTMpAeo#MaBsw6D-%2=k zaJ^UU5*@$+83&}oFoxlrbV*?DzEwV_W5wiczN8bzugQp%tW5MwEyRtEa z7_!t;(^u$3CZ&K2>3y*AhJF&r+o@P(=2s%+okcj-*XR7VfBM-x>yZ$(k`aGOXo^fZ zObyjEN3}XX(F)a+1g%n^j#EyTPGDTN*ri<-Sj=`nxsUhYTNB7iO;Pnsjo8C|RWPv= z;bNY~R-SHyybLM-dJ&<_ovO{HH^e0plF3=J;W@n@eV!nmBBO=P?a8-jW@@?~q%bhi z3G+mP9n2`nl(@No_saZ*^tX@F`>AS`RbvPhuBWFTJYv$9)>fY#80kcuYjR&!DXhZR zE-}$LzQftuuZ40yl8w-J6bS0+=B-ldEhCtVeNa z74C83o_IGCtwk>Lkfak+O#Bpft886je{Y|b6>sbgxe+22HY{vv$2EaOV{uAO#~_~w z5V-gko}tY-i}FHh?OS*bS;b|;rM_iHzPLscF`tEOA2V`Gyf>=O6ol5+4^fPC_b|L)r!5)V=o>cHat5RW<4<(%8mLZFR}Z)G8A7V};8+2q^xNg;xxUX&%x_F! zNe;ajz`s-Fo`7B>L|D(kc<*1s>y4&?v2{J_+9L{|`oG2NAEt8#29B*KRt&u;=hv)G zu+32jB+^}HP9`_; zuxt&WljZwDP=y0qS;E4}2Ve`+K0f&FDi#jEsB=s3VPuWwg$A>8VQRh^R_erOx!W=Y zLHPR75XQq|R&e-?j z?4Bz}r0R|!OJnbR|3$QC6#-pUVxg%Wv7g^9NI?ztAb=$iTM;9s5&DvJr-NccWS`^G zSh4k+AcQsD-H_s}U+H^EKQ1h$g@1nZ09gpcL1-nZ$c(_K)EG&&@jhFYZeJ eTMYT$f3c8uT)^g!{CgVk2U$r)V5PWm;Qs=0AbX1d diff --git a/index.html b/index.html index a425934..ad776dc 100644 --- a/index.html +++ b/index.html @@ -1,6 +1,5 @@ - - + diff --git a/openNote/controllers/folderController.js b/openNote/controllers/folderController.js index 71dd085..d8a6685 100644 --- a/openNote/controllers/folderController.js +++ b/openNote/controllers/folderController.js @@ -94,7 +94,7 @@ openNote.controller("folderController", ["$scope", $scope.loadCurrentFolder = function() { //Load the folder if (!$routeParams.id) { - $scope.currentFolder = { //FIXME config special root + $scope.currentFolder = { //FIXME multiple DBs _id: null, name: "Home" }; @@ -143,6 +143,7 @@ openNote.controller("folderController", ["$scope", $scope.$apply(); }).catch(function(error) { throw error; + console.error(error); //FIXME conflict resolution }); }, @@ -190,14 +191,19 @@ openNote.controller("folderController", ["$scope", var createFolder = function(folder) { folder.type = "folder"; storageService.post(folder).then(function(response) { - if (!response.ok) - throw "//FIXME"; + if (!response.ok){ + alertify.error("There was an error creating the folder"); + console.error(response); + throw response; + } $rootScope.$emit("reloadListView", {}); $location.url("/folder/" + response.id); $scope.$apply(); }).catch(function(error) { - console.log(error); //FIXME + alertify.error("There was an error creating the folder"); + console.error(error); + throw error; }); }; diff --git a/openNote/controllers/noteController.js b/openNote/controllers/noteController.js index 46723ec..d2d2448 100644 --- a/openNote/controllers/noteController.js +++ b/openNote/controllers/noteController.js @@ -134,8 +134,12 @@ openNote.controller("noteController", ["$scope", * Callback after successful save to reload note */ var saveCallback = function(response) { - if (!response.ok) - throw "//FIXME"; //FIXME + if (!response.ok){ + alertify.error("There was an error saving the note"); + console.error(response); + throw response; + } + detachWindowUnload(); //Tags diff --git a/openNote/controllers/searchController.js b/openNote/controllers/searchController.js index cf829b1..45e528f 100644 --- a/openNote/controllers/searchController.js +++ b/openNote/controllers/searchController.js @@ -19,25 +19,27 @@ openNote.controller("searchController", ["$scope", $scope.searchString = $routeParams.id; //Default + // Handle search button $scope.search = function() { - $location.url("/search/" + $scope.searchString); + if(!$scope.searchString || !$scope.searchString.length) + return alertify.error("A query must be specified"); + $location.url("/search/" + encodeURIComponent($scope.searchString)); }; + //Load results from URI parameter $scope.loadResults = function() { - if (!$routeParams.id) - return; - + var searchRegex = new RegExp($routeParams.id,"i"); alertify.log("Search started"); $scope.results = []; storageService.allDocs().then(function(result) { result.rows.filter(storageService.folderFilter).forEach(function(folder) { // search folders - if (folder.doc.name.match($routeParams.id)) //search folder name + if (folder.doc.name.match(searchRegex)) //search folder name return $scope.results.push(folder); }); result.rows.filter(storageService.noteFilter).forEach(function(note) { //Search notes - if (note.doc.title.match($routeParams.id) || note.doc.note.match($routeParams.id)) //search note name and title + if (note.doc.title.match(searchRegex) || note.doc.note.match($routeParams.id)) //search note name and title return $scope.results.push(note); }); $scope.$apply(); @@ -46,7 +48,8 @@ openNote.controller("searchController", ["$scope", }; - //Load results - $timeout($scope.loadResults); + //Load results if set + if ($routeParams.id) + $timeout($scope.loadResults); } ]); diff --git a/openNote/controllers/tagListController.js b/openNote/controllers/tagListController.js index 2203a00..0ca606d 100644 --- a/openNote/controllers/tagListController.js +++ b/openNote/controllers/tagListController.js @@ -27,8 +27,11 @@ openNote.controller("tagListController", [ $scope.tags.push(tag); $scope.$apply(); - }).catch(function() { - //TODO + }).catch(function(error) { + if(error.status ==404) + return;//Ignore + alertify.error("There was an error."); + console.error(error); }); }; diff --git a/openNote/directives/folderContentsDirective.js b/openNote/directives/folderContentsDirective.js index 1d514a8..8545890 100644 --- a/openNote/directives/folderContentsDirective.js +++ b/openNote/directives/folderContentsDirective.js @@ -17,13 +17,11 @@ openNote.directive("folderContentsDirective", [ * fade out all folders */ $scope.fadeOut = function(callback) { - $(".note").fadeTo(config.fadeSpeedShort(), 0, function() { - $scope.$apply(function() { - callback(); - }); - }); + var selector = $(".note, .folder"); + if(!selector.length)//If its a blank folder just run the callback + return callback(); - $(".folder").fadeTo(config.fadeSpeedShort(), 0, function() { + selector.fadeTo(config.fadeSpeedShort(), 0, function() { $scope.$apply(function() { callback(); }); @@ -34,7 +32,7 @@ openNote.directive("folderContentsDirective", [ * Load a folder * @param folder- the folder to load */ - $scope.loadFolder = function(folder) { //TODO DRY + $scope.loadFolder = function(folder) { $scope.fadeOut(function() { $location.url("/folder/" + folder.doc._id); }); @@ -44,7 +42,7 @@ openNote.directive("folderContentsDirective", [ * Load a note * @param note - load a note */ - $scope.loadNote = function(note) { //TODO DRY + $scope.loadNote = function(note) { $scope.fadeOut(function() { $location.url("/note/" + note.id); }); diff --git a/package.json b/package.json index b4dcf48..40f8718 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "grunt-contrib-connect": "^1.0.2", "grunt-contrib-jshint": "^1.0.0", "grunt-contrib-less": "^0.11.1", - "grunt-contrib-watch": "^0.6.1", "grunt-manifest": "^0.4.0", "grunt-shell": "^0.7.0", "script-loader": "^0.7.2", @@ -40,7 +39,8 @@ "webpack-dev-server": "^2.9.5" }, "scripts": { - "test": "testcafe chrome ./test/e2e/test.js -e -c 3", + "test": "testcafe chrome ./test/e2e/test.js --skip-js-errors -c 3", + "testSingle": "testcafe chrome ./test/e2e/test.js --skip-js-errors", "dev": "webpack-dev-server --open --hot --config ./build/webpack.dev.config.js", "build": "webpack --progress --hide-modules --config ./build/webpack.prod.config.js" } diff --git a/test/e2e/test.js b/test/e2e/test.js index faaec66..9701662 100644 --- a/test/e2e/test.js +++ b/test/e2e/test.js @@ -1,191 +1,88 @@ // jshint ignore: start - -import { Selector, ClientFunction } from "testcafe"; // first import testcafe selectors - -const WAIT_TIME = 500; // Time to wait after some actions to give angular time to re render - -fixture`Getting Started` +import { ClientFunction} from "testcafe"; // first import testcafe selectors +fixture `OpenNote` .page `http://127.0.0.1:8080/` .afterEach(async testController => {//Clean up local storage and local db let clean = ClientFunction(() => { localStorage.clear(); return PouchDB("openNote").destroy() - }); + }); - await clean(); + await clean(); }); -/** - * Create a folder. Expects to be in a folder partial. - * @param {[type]} testController [description] - * @param {[type]} name - name folder - * @return {testController} - testController object - */ -let createFolder = (testController, name) => { - return testController.click("#newFolder") - .typeText("#alertify-text", name) - .click("#alertify-ok"); -} - - -/** - * Create a note. Expects to be in a sub folder in a folder partial. - * @param {[type]} testController [description] - * @param {[type]} title [description] - * @param {[type]} note [description] - * @return {testController} - testController object - */ -let createNote = (testController, title, note) => { - let typeString = note.split("") - - typeString.forEach((char, index)=>{ - if(char != " ") - return; - typeString[index]="space"; - }); - typeString = typeString.join(" "); - - return testController.click("#newNote") - .typeText("#noteName", title,{replace:true}) - .click(".CodeMirror-scroll") - .pressKey(typeString) - .click("#save") -} /** - * Edits a note. Expects to be on a note partial - * @param {[type]} testController [description] - * @param {[type]} title [description] - * @param {[type]} note [description] + * List of helper functions */ -let editNote = async (testController, title, note) => { - const CLEAR_STRING = "ctrl+a backspace" - let typeString = note.split("") - - typeString.forEach((char, index)=>{ - if(char != " ") - return; - typeString[index]="space"; - }); - typeString = typeString.join(" "); - - await testController.click("#edit") - .typeText("#noteName", title,{replace:true}) - .click(".CodeMirror-scroll") - .pressKey(CLEAR_STRING) - .pressKey(typeString) - .click("#save") -} - -test("Create Folder", async testController => { - //Arrange - - //Act - let folderName="TestFolder" - await createFolder(testController, folderName).wait(WAIT_TIME) - - //Asert - let result = await Selector("#currentFolder").innerText;//#Stupid should really just be sync - await testController.expect(result.trim()).eql(folderName); -}); - -test("Create note", async testController => { - //Arrange - - //Act - let title="TestNote"; - let tag = "#Something" - let note = `Now is the time for all good men to come to the aid of their country. ${tag}`; - - await createFolder(testController, "NoteTestFolder") - .wait(WAIT_TIME) - - await createNote(testController, title, note) - - //Asert - let titleActual = await Selector("#noteName").value; - let noteActual = await Selector("#note").innerText;//#Stupid should really just be sync - let tagActual = await Selector("#sideBar ul li:first-child ").innerText; - await testController.expect(titleActual).eql(title); - await testController.expect(noteActual.trim()).eql(note); - await testController.expect(tagActual).eql(tag.toLowerCase()); - -}); - -test("Edit note", async testController => { - //Arrange - - //Act - let title="TestNote"; - let tag = "#Something" - let note = `Now is the time for all good men to come to the aid of their country. ${tag}`; - - await createFolder(testController, "NoteTestFolder") - .wait(WAIT_TIME) - - await createNote(testController, title, note) - - title="TestNote2"; - tag = "#SomethingElse" - note = `YO ${tag}`; - - await editNote(testController, title, note) - - //Asert - let titleActual = await Selector("#noteName").value; - let noteActual = await Selector("#note").innerText;//#Stupid should really just be sync - let tagActual = await Selector("#sideBar ul li:first-child ").innerText; - await testController.expect(titleActual).eql(title); - await testController.expect(noteActual.trim()).eql(note); - await testController.expect(tagActual).eql(tag.toLowerCase()); -}); - -test("Delete note", async testController => { - //Arrange - - //Act - let folderName = "NoteTestFolder"; - await createFolder(testController, folderName) - .wait(WAIT_TIME); - - await createNote(testController, "TestNote", "Now is the time for all good men to come to the aid of their country. #something"); - - await testController.click("#edit") - .click("#removeNote") - .click("#alertify-ok"); - - //Asert - await testController.expect(Selector("#sideBar ul li:first-child ").innerText).eql("No tags found. Add a # to a note to add a tag."); - let result = await Selector("#currentFolder").innerText;//Make sure we are back to parent folder - await testController.expect(result.trim()).eql(folderName); +const helper = { + /** + * Create a folder. Expects to be in a folder partial. + * @param {[type]} testController [description] + * @param {[type]} name - name folder + * @return {testController} - testController object + */ + createFolder: (testController, name) => { + return testController.click("#newFolder") + .typeText("#alertify-text", name) + .click("#alertify-ok"); + }, + + + /** + * Create a note. Expects to be in a sub folder in a folder partial. + * @param {[type]} testController [description] + * @param {[type]} title [description] + * @param {[type]} note [description] + * @return {testController} - testController object + */ + createNote: (testController, title, note) => { + let typeString = note.split("") + + typeString.forEach((char, index)=>{ + if(char != " ") + return; + typeString[index]="space"; + }); + typeString = typeString.join(" "); + + return testController.click("#newNote") + .typeText("#noteName", title,{replace:true}) + .click(".CodeMirror-scroll") + .pressKey(typeString) + .click("#save") + }, + + /** + * Edits a note. Expects to be on a note partial + * @param {[type]} testController [description] + * @param {[type]} title [description] + * @param {[type]} note [description] + */ + editNote: async (testController, title, note) => { + const CLEAR_STRING = "ctrl+a backspace" + let typeString = note.split("") + + typeString.forEach((char, index)=>{ + if(char != " ") + return; + typeString[index]="space"; + }); + typeString = typeString.join(" "); + + await testController.click("#edit") + .typeText("#noteName", title,{replace:true}) + .click(".CodeMirror-scroll") + .pressKey(CLEAR_STRING) + .pressKey(typeString) + .click("#save") + } + } + +let path = __dirname+"/usecases/"; +require("fs").readdirSync(path).forEach(function(file) { + let testInfo = require(path + file)(helper); + test(testInfo.name, testInfo.test);//There has to be a better way to do this. If this function is not here atleast onces tests will not load from other files. If it is, tests can be defined in imports. }); -test("Delete folder tree", async testController => { - //Create first level - let firstLevelTag="#firstLevel" - await createFolder(testController, "NoteTestFolder") - .wait(WAIT_TIME) - await createNote(testController, "TestNote", `Quick. ${firstLevelTag}`).wait(WAIT_TIME); - await testController.expect(await Selector("#sideBar ul li:first-child ").innerText).eql(firstLevelTag.toLowerCase()); - - //Create second level - await testController.click("#goToParentFolder"); - await createFolder(testController, "SubFolder") - .wait(WAIT_TIME) - await createNote(testController, "Sub Note", "Bla #foo").wait(WAIT_TIME); - await testController.expect(Selector("#sideBar ul").childElementCount).eql(2);//We should have two tags - - //Delete it - await testController.click("#home") - .click(".folderPartial div.folder") - .click("#currentFolder") - .click("#delete") - .click("#alertify-ok") - .wait(WAIT_TIME); - - - await testController.expect(Selector("#sideBar ul li:first-child").innerText).eql("No tags found. Add a # to a note to add a tag."); //Make sure no tags - let result = await Selector("#currentFolder").innerText - await testController.expect(result.trim()).eql("Home");;//Make sure we are back to parent folder - await testController.expect(Selector(".folderPartial div.folder").length).eql(0);//Make sure there are no folders anymore -}); +//Remember you can do a .debug() to hault execution to debug diff --git a/test/e2e/usecases/folder.create.test.js b/test/e2e/usecases/folder.create.test.js new file mode 100644 index 0000000..72fe3a9 --- /dev/null +++ b/test/e2e/usecases/folder.create.test.js @@ -0,0 +1,20 @@ +// jshint ignore: start +import { Selector} from "testcafe"; // first import testcafe selectors +const WAIT_TIME = 1250; // Time to wait after some actions to give angular time to re render + +module.exports = (helper)=>{ + return { + name: "Create Folder", + test: async testController => { + //Arrange + + //Act + let folderName="TestFolder"; + await helper.createFolder(testController, folderName).wait(WAIT_TIME); + + //Asert + let result = await Selector("#currentFolder").innerText;//#Stupid should really just be sync + await testController.expect(result.trim()).eql(folderName); + } + }; +}; diff --git a/test/e2e/usecases/folder.delete.test.js b/test/e2e/usecases/folder.delete.test.js new file mode 100644 index 0000000..41d7b3e --- /dev/null +++ b/test/e2e/usecases/folder.delete.test.js @@ -0,0 +1,46 @@ +// jshint ignore: start +import { Selector, ClientFunction } from "testcafe"; // first import testcafe selectors +const WAIT_TIME = 1250; // Time to wait after some actions to give angular time to re render + +module.exports = (helper)=>{ + return { + name: "Delete folder and make sure other folders are fine", + test: async testController => { + //Create first folder + let firstLevelTag="#firstLevel" + await helper.createFolder(testController, "NoteTestFolder") + .wait(WAIT_TIME) + await helper.createNote(testController, "TestNote", `Quick. ${firstLevelTag}`).wait(WAIT_TIME); + await testController.expect(await Selector("#sideBar ul li:first-child ").innerText).eql(firstLevelTag.toLowerCase()); + + //Create second folder + let secondFolderTitle="ZZZZ";//Folders are displayed alphabetically + let secondNoteTitle ="Sub Note"; + let secondNoteTag = "#foo"; + await testController.click("#home") + await helper.createFolder(testController, secondFolderTitle) + .wait(WAIT_TIME) + await helper.createNote(testController, secondNoteTitle, `Bla ${secondNoteTag}`).wait(WAIT_TIME); + await testController.expect(Selector("#sideBar ul").childElementCount).eql(2);//We should have two tags + + //Delete it + await testController.click("#home") + .click(".folderPartial div.folder:first-child") + .wait(WAIT_TIME) + .click("#currentFolder") + .click("#delete") + .click("#alertify-ok") + .wait(WAIT_TIME); + + + //Assert Tags + await testController.expect(Selector("#sideBar ul li:first-child").innerText).eql(secondNoteTag); //Make sure no tags + await testController.expect(Selector("#sideBar ul").count).eql(1);//We should have one tags + + //Assert folders + await testController.wait(WAIT_TIME).expect(Selector(".folderPartial div.folder").count).eql(1); + let result = await Selector(".folderPartial div.folder h4").innerText + await testController.expect(result.trim()).eql(secondFolderTitle);//Make sure we are back to parent folder + } + }; +}; diff --git a/test/e2e/usecases/folder.deleteTree.test.js b/test/e2e/usecases/folder.deleteTree.test.js new file mode 100644 index 0000000..71a0b93 --- /dev/null +++ b/test/e2e/usecases/folder.deleteTree.test.js @@ -0,0 +1,40 @@ +// jshint ignore: start +import { Selector, ClientFunction } from "testcafe"; // first import testcafe selectors +const WAIT_TIME = 1250; // Time to wait after some actions to give angular time to re render + +module.exports = (helper)=>{ + + return { + name: "Delete folder tree", + test: async testController => { + //Create first level + let firstLevelTag="#firstLevel" + await helper.createFolder(testController, "NoteTestFolder") + .wait(WAIT_TIME) + await helper.createNote(testController, "TestNote", `Quick. ${firstLevelTag}`).wait(WAIT_TIME); + await testController.expect(await Selector("#sideBar ul li:first-child ").innerText).eql(firstLevelTag.toLowerCase()); + + //Create second level + await testController.click("#goToParentFolder"); + await helper.createFolder(testController, "SubFolder") + .wait(WAIT_TIME) + await helper.createNote(testController, "Sub Note", "Bla #foo").wait(WAIT_TIME); + await testController.expect(Selector("#sideBar ul").childElementCount).eql(2);//We should have two tags + + //Delete it + await testController.click("#home") + .click(".folderPartial div.folder") + .wait(WAIT_TIME) + .click("#currentFolder") + .click("#delete") + .click("#alertify-ok") + .wait(WAIT_TIME); + + + await testController.expect(Selector("#sideBar ul li:first-child").innerText).eql("No tags found. Add a # to a note to add a tag."); //Make sure no tags + let result = await Selector("#currentFolder").innerText + await testController.expect(result.trim()).eql("Home");//Make sure we are back to parent folder + await testController.expect(Selector(".folderPartial div.folder").count).eql(0);//Make sure there are no folders anymore + } + }; +}; diff --git a/test/e2e/usecases/note.create.test.js b/test/e2e/usecases/note.create.test.js new file mode 100644 index 0000000..faa20e0 --- /dev/null +++ b/test/e2e/usecases/note.create.test.js @@ -0,0 +1,29 @@ +// jshint ignore: start +import { Selector} from "testcafe"; // first import testcafe selectors +const WAIT_TIME = 1250; // Time to wait after some actions to give angular time to re render +module.exports = (helper)=>{ + return { + name:"Create note", + test: async testController => { + //Arrange + + //Act + let title="TestNote"; + let tag = "#Something" + let note = `Now is the time for all good men to come to the aid of their country. ${tag}`; + + await helper.createFolder(testController, "NoteTestFolder") + .wait(WAIT_TIME) + + await helper.createNote(testController, title, note) + + //Asert + let titleActual = await Selector("#noteName").value; + let noteActual = await Selector("#note").innerText;//#Stupid should really just be sync + let tagActual = await Selector("#sideBar ul li:first-child ").innerText; + await testController.expect(titleActual).eql(title); + await testController.expect(noteActual.trim()).eql(note); + await testController.expect(tagActual).eql(tag.toLowerCase()); + } + }; +}; diff --git a/test/e2e/usecases/note.delete.test.js b/test/e2e/usecases/note.delete.test.js new file mode 100644 index 0000000..b632171 --- /dev/null +++ b/test/e2e/usecases/note.delete.test.js @@ -0,0 +1,28 @@ +// jshint ignore: start +import { Selector, ClientFunction } from "testcafe"; // first import testcafe selectors +const WAIT_TIME = 1250; // Time to wait after some actions to give angular time to re render + +module.exports = (helper)=>{ + return { + name: "Delete note", + test: async testController => { + //Arrange + + //Act + let folderName = "NoteTestFolder"; + await helper.createFolder(testController, folderName) + .wait(WAIT_TIME); + + await helper.createNote(testController, "TestNote", "Now is the time for all good men to come to the aid of their country. #something"); + + await testController.click("#edit") + .click("#removeNote") + .click("#alertify-ok"); + + //Asert + await testController.expect(Selector("#sideBar ul li:first-child ").innerText).eql("No tags found. Add a # to a note to add a tag."); + let result = await Selector("#currentFolder").innerText;//Make sure we are back to parent folder + await testController.expect(result.trim()).eql(folderName); + } + }; +}; diff --git a/test/e2e/usecases/note.edit.test.js b/test/e2e/usecases/note.edit.test.js new file mode 100644 index 0000000..4ccfc21 --- /dev/null +++ b/test/e2e/usecases/note.edit.test.js @@ -0,0 +1,36 @@ +// jshint ignore: start +import { Selector, ClientFunction } from "testcafe"; // first import testcafe selectors +const WAIT_TIME = 1250; // Time to wait after some actions to give angular time to re render + +module.exports = (helper)=>{ + return { + name: "Edit note", + test: async testController => { + //Arrange + + //Act + let title="TestNote"; + let tag = "#Something" + let note = `Now is the time for all good men to come to the aid of their country. ${tag}`; + + await helper.createFolder(testController, "NoteTestFolder") + .wait(WAIT_TIME) + + await helper.createNote(testController, title, note) + + title="TestNote2"; + tag = "#SomethingElse" + note = `YO ${tag}`; + + await helper.editNote(testController, title, note) + + //Asert + let titleActual = await Selector("#noteName").value; + let noteActual = await Selector("#note").innerText;//#Stupid should really just be sync + let tagActual = await Selector("#sideBar ul li:first-child ").innerText; + await testController.expect(titleActual).eql(title); + await testController.expect(noteActual.trim()).eql(note); + await testController.expect(tagActual).eql(tag.toLowerCase()); + } + }; +}; diff --git a/test/karma.conf.js b/test/karma.conf.js deleted file mode 100644 index 292714e..0000000 --- a/test/karma.conf.js +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = function(config){//TODO move this stuff into another project - config.set({ - basePath : "../", - files : [ - "node_modules/es5-shim/es5-shim.min.js", - "node_modules/angular/angular.js", - "node_modules/angular-mocks/angular-mocks.js", - "node_modules/angular-route/angular-route.js", - "node_modules/angular-resource/angular-resource.js", - "node_modules/angular-sanitize/angular-sanitize.js", - "node_modules/angular-animate/angular-animate.js", - "node_modules/pouchdb/dist/pouchdb.min.js", - "node_modules/jquery/jquery.js", - "openNote/openNote.js", - "openNote/**/*.js", - "OpenNote.Test/**/*.js" - ], - autoWatch : false, - frameworks: ["jasmine"], - browsers : ["Firefox"], - plugins : [ - "karma-phantomjs-launcher", - "karma-jasmine" - ], - junitReporter : { - outputFile: "test_out/unit.xml", - suite: "unit" - } - }); -}; diff --git a/test/unit/folder.js b/test/unit/folder.js deleted file mode 100644 index 3fc1205..0000000 --- a/test/unit/folder.js +++ /dev/null @@ -1,62 +0,0 @@ -var createFolder = function(id,parentFolderID, name){ - return { - "_id": id, - "parentFolderID": parentFolderID, - "name": name - }; -}; - -//TODO storageService save folder twice - -describe("folderController", function() { - var $scope; - var createController; - var $rootScope; - - //load openNote module - beforeEach(module("openNote")); - - /** - * Setup the folder controller - */ - beforeEach(inject(function($controller, $rootScope){ - $scope = $rootScope.$new(); - this.$rootScope=$rootScope; - - $rootScope.buttons=[]; - - /** - * Factory to create mock controller - */ - createController = function(scope, rootScope, location, routeParams, storageService, config, timeout){ - return $controller("folderController", - {$scope:scope}, - {$rootScope:rootScope}, - {$location:location}, - {$routeParams: routeParams}, - {storageService: storageService}, - {config:config}, - {$timeout:timeout} - ); - }; - })); - - it("should not show folder edit buttons if current folder is home", inject(function($location, config, $timeout) {//inject location and config - createController($scope, $rootScope, $location, [], null, config, $timeout); - $scope.currentFolder = createFolder(null,null,null); - - expect($scope.folderEditMode).toEqual(false); - $scope.activateFolderEditMode();//simulate title click - expect($scope.folderEditMode).toEqual(false); - - })); - - it("should show folder edit buttons if current folder is not home", inject(function($location, config, $timeout) {//inject location and config - createController($scope, $rootScope, $location, [], null, config, $timeout); - $scope.currentFolder = createFolder(123,null,"Not Home"); - - expect($scope.folderEditMode).toEqual(false); - $scope.activateFolderEditMode();//simulate title click - expect($scope.folderEditMode).toEqual(true); - })); -}); From 89b0145584e362623539aa9910fb5b9046eba2bd Mon Sep 17 00:00:00 2001 From: FoxUSA Date: Sat, 24 Feb 2018 23:16:00 -0700 Subject: [PATCH 15/17] Updated documentation and build cleanup --- .travis.yml | 5 ----- Gruntfile.js | 4 ++-- README.md | 2 +- docs/Build.md | 2 +- docs/History.md | 13 +++++++++---- docs/HowToUse.md | 4 ++-- package.json | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 967a59c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - node -before_script: - - npm install -g grunt-cli diff --git a/Gruntfile.js b/Gruntfile.js index 75242a1..a6db081 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -104,9 +104,9 @@ module.exports = function(grunt) { shell: { clean: { - command: ["rm -rf dist", + command: ["rm -rf dist webpack_files", "cd openNote/style/invert/", - "rm -rf dark light" + "rm -rf dark light", ].join("&&") }, test: { diff --git a/README.md b/README.md index 9a77f45..779ab8b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# OpenNote [![Build Status](https://travis-ci.org/FoxUSA/OpenNote.png?branch=master)](https://travis-ci.org/FoxUSA/OpenNote) +# OpenNote ![][responsive] OpenNote is a progressive web application(PWA)/HTML5 offline app that was built to be a open source(MIT License), web based text editor/note taking software. diff --git a/docs/Build.md b/docs/Build.md index cf2a84f..1ca874b 100644 --- a/docs/Build.md +++ b/docs/Build.md @@ -29,7 +29,7 @@ You can see a full list of commands by running `grunt --help`. Below are the most important commands - `grunt default` or `grunt` to have webpack in development mode - `grunt ci` run linting and tests -- `grunt deploy` Package up the project +- `grunt deploy` Package up the project into the `dist` folder. Creates a zip with the version number that can be uploaded to Github. To develop tests diff --git a/docs/History.md b/docs/History.md index 93b69c0..402a61b 100644 --- a/docs/History.md +++ b/docs/History.md @@ -3,12 +3,17 @@ Back in 2013 OneNote was started. Back then Microsoft OneNote did not have a full featured web interface. I used that at the time and had many notebooks. I wanted a way of taking those notes with me on my phone. I had limited data and wanted an application that would sync all my notes, let me modify them, and sync them back. I tried a bunch of applications and there were none that fulfilled my offline and tree structure requirements. ## Open note -OpenNote has a text only design. No icons or symbols other than ascii non alphabetical characters. The application just so happened to end up this way. It has a very clean feel to it and does not distract you. I would like to keep this going forward -### Generation Alpha +OpenNote has a text only design. No icons or symbols other than ascii non alphabetical characters. The application just so happened to end up this way. It has a very clean feel to it and does not distract you. I would like to keep this going forward. + +**Why emphasis on text?** Text is a really old medium for storing information. All sorts of style and support for it. Computers store text really efficiently in comparison to blob data like images. + + +### OpenNote Generations +#### Generation Alpha The first version of OpenNote was a PHP fat application. Views were prepared by PHP and sent to the browser via a full load or AJAX. -### Generation Beta +#### Generation Beta Second major revision was the switch to the then booming Angular 1 framework and use HTML5 application manifest and CouchDB to provided offline access and syncing. -### Current Generation +#### Current Generation The most recent efforts have been to add modern features. Tags, markdown, and a CLI. diff --git a/docs/HowToUse.md b/docs/HowToUse.md index 0409429..db400e9 100644 --- a/docs/HowToUse.md +++ b/docs/HowToUse.md @@ -8,7 +8,7 @@ ^ ^ | | | |PouchDB sync - |Pre-signed urls | + |Pre-signed urls (De-coupled) | | | v v +----+-------------------------+ +----------------------------+----------+ @@ -23,7 +23,7 @@ Component | Purpose --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- OpenNote | A PWA(Offline compatible) web application that allows you edit and access notes. CouchDB | Couch DB is a database that stores your notes. When this is setup, you do not need to worry if your phone gets lost. When fully replicated, your notes will be safely stored in CouchDB. CouchDB also allows multiple browsers to sync. So you can have your notes on all your devices. -Minio | Minio is a blob storage server that implements the AWS S3 API. This allows you to upload your images and non text files for use with OpenNote/ +Minio | Minio is a blob storage server that implements the AWS S3 API. This allows you to upload your images and non text files for use with OpenNote. [OpenNote-CLI](https://github.com/FoxUSA/OpenNote-CLI) | OpenNote CLI syncs the database to disk. This allows you to use other editors like Atom to create and edit notes. ## General diff --git a/package.json b/package.json index 40f8718..20bc139 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "OpenNote", - "version": "18.03.00-Alpha", + "version": "18.03.00", "description": "", "main": "Gruntfile.js", "author": "Jacob Liscom", From 04ffce6a79767bf6a97b6cae846af01f56715f13 Mon Sep 17 00:00:00 2001 From: FoxUSA Date: Sun, 25 Feb 2018 13:33:34 -0700 Subject: [PATCH 16/17] Fixed display, refactor tag controller, fixed tag css --- docs/Build.md | 6 ++-- docs/HowToUse.md | 18 ------------ docs/Install.md | 28 +++++++++++++++++-- index.html | 4 +-- openNote/controllers/noteController.js | 9 +----- .../settings/databaseController.js | 2 +- openNote/controllers/tagController.js | 4 ++- .../directives/folderContentsDirective.js | 2 +- openNote/openNote.config.js | 2 +- openNote/openNote.js | 11 +++++--- openNote/partials/tagListPartial.html | 4 +-- openNote/partials/tagPartial.html | 12 +------- openNote/style/invert/style.less | 7 +++-- 13 files changed, 50 insertions(+), 59 deletions(-) diff --git a/docs/Build.md b/docs/Build.md index 1ca874b..adad8bf 100644 --- a/docs/Build.md +++ b/docs/Build.md @@ -4,14 +4,12 @@ - Grunt `npm install -g grunt-cli` ## Build -Clone [this project](https://github.com/FoxUSA/OpenNote) an the [SharedServices Project](https://github.com/FoxUSA/OpenNoteService-PHP) - -My project folder structure is setup as follows +Clone the projects and set them up in the structure below ``` Some working folder ├─ OpenNote ├─ OpenNote-SharedServices -├─ OpenNote-Docer +├─ OpenNote-Docker └─ OpenNote-CLI ``` diff --git a/docs/HowToUse.md b/docs/HowToUse.md index db400e9..1ed9deb 100644 --- a/docs/HowToUse.md +++ b/docs/HowToUse.md @@ -46,24 +46,6 @@ Once you click on a note you'll will be presented with it in a read only view. ![][seedsedit] This will bring you to the editor. Once you are all done editing, click "Save" to store the note. -## Syncing -By default OpenNote is storing info in your browser. Until you setup syncing, you are at risk of lousing your notes. To setup syncing. From the home page click `Settings`, then click database. On the right hand side of the panel you will see a Replication url field. This expect a url to your couchDB database in the form of `$protocol://$user:$password@$serverurl:$port/$database`. - -For example if your server information is as follows: - -Item | Value ---- | --- -protocol | http -user | admin -password | password -serverurl | 127.0.0.1 -port | 6984 -database | opennote - -then your replication url would be `http://admin:password@127.0.0.1:6984/opennote` - -You will see an alert if replication is working. - [plants]: ./images/plants.png [seedsedit]: ./images/seedsEdit.png [seedsview]: ./images/seedsView.png diff --git a/docs/Install.md b/docs/Install.md index 4d8d1bf..967fc14 100644 --- a/docs/Install.md +++ b/docs/Install.md @@ -28,11 +28,35 @@ services: command: server /data ``` -## Start -`docker-compose up -d` to start +## Setup +- [ ] `docker-compose up -d` to start +- CouchDB + - [ ] Go to `http://$serverurl:5984/_utils/#_config/nonode@nohost/cors` and enable CORS for your domain. + - [ ] Go to `http://$serverurl:5984/_utils/#_config/nonode@nohost` and set `require_valid_user` to true. If you are unable to get to the login screen after setting that, you can access it via `http://$serverurl:5984/_utils/#login` + - [ ] Setup SSL [via this guide](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=48203146) //TODO +- Minio + - [ ] Setup SSL //TODO https://docs.minio.io/docs/how-to-secure-access-to-minio-server-with-tls + - [ ] Create OpenNote bucket +## Syncing +By default OpenNote is storing info in your browser. Until you setup syncing, you are at risk of lousing your notes. To setup syncing. From the home page click `Settings`, then click database. On the right hand side of the panel you will see a Replication url field. This expect a url to your couchDB database in the form of `$protocol://$user:$password@$serverurl:$port/$database`. + +For example if your server information is as follows: + +Item | Value +--- | --- +protocol | http +user | admin +password | password +serverurl | 127.0.0.1 +port | 5984 +database | opennote + +then your replication url would be `http://admin:password@127.0.0.1:6984/opennote` + +You will see an alert if replication is working. ## Uninstall If you ever want to shutdown OpenNote run `docker-compose down` in the same folder as `docker-compose.yml`. This will shut down the containers associated with OpenNote. diff --git a/index.html b/index.html index ad776dc..301dedf 100644 --- a/index.html +++ b/index.html @@ -18,8 +18,8 @@ - - + +
    diff --git a/openNote/controllers/noteController.js b/openNote/controllers/noteController.js index d2d2448..aa3799f 100644 --- a/openNote/controllers/noteController.js +++ b/openNote/controllers/noteController.js @@ -111,13 +111,6 @@ openNote.controller("noteController", ["$scope", lineNumbers: true, indentUnit: 4 }); - - // var resize = function() { - // $(".CodeMirror").css({"height": ($(window).height()*0.75 )+ "px"}); - // }; - // window.onresize = resize; - // resize(); - }); }; @@ -139,7 +132,7 @@ openNote.controller("noteController", ["$scope", console.error(response); throw response; } - + detachWindowUnload(); //Tags diff --git a/openNote/controllers/settings/databaseController.js b/openNote/controllers/settings/databaseController.js index c7edeef..41afe4b 100644 --- a/openNote/controllers/settings/databaseController.js +++ b/openNote/controllers/settings/databaseController.js @@ -24,7 +24,7 @@ openNote.controller("databaseController", ["$scope", * Save replication settings */ $scope.save = function() { - storageService.setRemoteURL($scope.url); + storageService.setRemoteURL($scope.url);//TODO validate this with a regex or something $rootScope.$on("replicationComplete", function() { $rootScope.$emit("reloadListView", {}); }); diff --git a/openNote/controllers/tagController.js b/openNote/controllers/tagController.js index bc85efa..d498698 100644 --- a/openNote/controllers/tagController.js +++ b/openNote/controllers/tagController.js @@ -34,7 +34,9 @@ openNote.controller("tagController", ["$scope", var tags = map.tags[$scope.tag]; tags.forEach(function(tag) { storageService.get(tag).then(function(note) { - $scope.notes.push(note); + $scope.notes.push({ + doc:note + }); $scope.$apply(); }); }); diff --git a/openNote/directives/folderContentsDirective.js b/openNote/directives/folderContentsDirective.js index 8545890..026c5ff 100644 --- a/openNote/directives/folderContentsDirective.js +++ b/openNote/directives/folderContentsDirective.js @@ -44,7 +44,7 @@ openNote.directive("folderContentsDirective", [ */ $scope.loadNote = function(note) { $scope.fadeOut(function() { - $location.url("/note/" + note.id); + $location.url("/note/" + note.doc._id); }); }; diff --git a/openNote/openNote.config.js b/openNote/openNote.config.js index af24fec..096dda2 100644 --- a/openNote/openNote.config.js +++ b/openNote/openNote.config.js @@ -8,7 +8,7 @@ openNote.value("config", { * Get current version */ getVersion: function(){ - return "17.02.01"; + return "18.03.00"; }, /** diff --git a/openNote/openNote.js b/openNote/openNote.js index cfd9753..3250e52 100644 --- a/openNote/openNote.js +++ b/openNote/openNote.js @@ -41,18 +41,20 @@ openNote.run([ "config", "tagService", "$http", + "$timeout", function($rootScope, $location, config, tagService, - $http) { + $http, + $timeout) { $rootScope.version = config.getVersion(); tagService.bindHandlers(); $rootScope.$on("$routeChangeStart", function() { //Initial entry after if logged in - if (!$rootScope.showMenu && !$rootScope.showSideBar) //make sure we only fade in/run once + if (!$rootScope.showUI) //make sure we only fade in/run once $rootScope.$emit("init"); }); @@ -60,8 +62,9 @@ openNote.run([ * Initialize app and start fade in */ $rootScope.$on("init", function() { - $rootScope.showMenu = true; - $rootScope.showSideBar = true; + $timeout(function(){ + $rootScope.showUI = true; + });//Wait for everything to make sure fade in is not skipped //Check for updates $http.get(config.getUpdateURL()).then( diff --git a/openNote/partials/tagListPartial.html b/openNote/partials/tagListPartial.html index 857adbd..966f75d 100644 --- a/openNote/partials/tagListPartial.html +++ b/openNote/partials/tagListPartial.html @@ -1,7 +1,5 @@ diff --git a/openNote/style/invert/style.less b/openNote/style/invert/style.less index f8d8c4e..9fe4212 100644 --- a/openNote/style/invert/style.less +++ b/openNote/style/invert/style.less @@ -288,14 +288,15 @@ img { // Note partial .notePartial{ .CodeMirror{ - border-radius:0 0 4px 4px;/*round the corners*/ - size: 75vh; + border-radius:4px;/*round the corners*/ + height: 75vh; } } // Folder partial -.folderPartial{ +.folderPartial, +.tagPartial{ #folderTitleBar{ padding: 0px 0px 15px 0px; overflow: hidden; From a0fbd94c16b70df3aacd0bd7780256a5e8e07433 Mon Sep 17 00:00:00 2001 From: FoxUSA Date: Sun, 11 Mar 2018 11:57:14 -0700 Subject: [PATCH 17/17] Finalize docs --- docs/Install.md | 66 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/docs/Install.md b/docs/Install.md index 967fc14..ece65bf 100644 --- a/docs/Install.md +++ b/docs/Install.md @@ -1,14 +1,25 @@ # How To Install + Put the following text in a `docker-compose.yml`. Make sure to set all the items marked `#TODO`. Also make sure this file is in a secure place. Your credentials are stored in it. + ``` version: "2" services: opennote: - image: foxusa/opennote - ports: - - "8080:80" + image: foxusa/opennote + volumes: + - ":/root/certs:ro"#TODO set this + ports: + - "80:80" + - "443:443" + - "6984:6984" #CouchDB Proxy + links: + - "couchdb:couchdb" couchdb: image: couchdb + volumes: + - ":/opt/couchdb/data" #TODO set this + - ":/root/certs:ro" #TODO set this ports: - "5984:5984" - "6984:6984" @@ -19,44 +30,61 @@ services: minio: image: minio/minio volumes: - - "/tmp/data:/data" #TODO set this + - ":/data" #TODO set this + - ":/root/.minio/certs:ro" #TODO set this ports: - "9000:9000" environment: MINIO_ACCESS_KEY: tests #TODO set this MINIO_SECRET_KEY: testssdfasdf #TODO set this command: server /data - ``` + ## Setup - [ ] `docker-compose up -d` to start -- CouchDB - - [ ] Go to `http://$serverurl:5984/_utils/#_config/nonode@nohost/cors` and enable CORS for your domain. - - [ ] Go to `http://$serverurl:5984/_utils/#_config/nonode@nohost` and set `require_valid_user` to true. If you are unable to get to the login screen after setting that, you can access it via `http://$serverurl:5984/_utils/#login` - - [ ] Setup SSL [via this guide](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=48203146) //TODO + > If you need to get into a container to configure something you can do so `docker-compose exec $container /bin/sh` IE `docker-compose exec couchdb /bin/sh`. +### SSL +Create a folder with a SSL `private.key` and `public.crt` this gets mounted by nginx and minio to encrypt connections. +the `public.crt` file should have your servers cert and the whole cert chain appended to it. -- Minio - - [ ] Setup SSL //TODO https://docs.minio.io/docs/how-to-secure-access-to-minio-server-with-tls - - [ ] Create OpenNote bucket +### OpenNote +- [ ] (Optional) Configure SSL: +Run `docker-compose exec opennote nano /etc/nginx/conf.d/default.conf` and use [this config](https://github.com/FoxUSA/OpenNote-Docker/blob/master/samples/nginx/default.conf) as a template. +- [ ] Run `docker-compose exec opennote nano /etc/nginx/nginx.conf` and add this line at the end of the http block +`client_max_body_size 100M;` + +### CouchDB +- [ ] Go to `http://$serverurl:5984/_utils/#_config/nonode@nohost/cors` and enable CORS for your domain. +- [ ] Go to `http://$serverurl:5984/_utils/#_config/nonode@nohost` and set `require_valid_user` to true. If you are unable to get to the login screen after setting that, you can access it via `http://$serverurl:5984/_utils/#login` + +### Minio +- [ ] Create OpenNote bucket + +>finally run `docker-compose restart to use the updated configurations`. ## Syncing + By default OpenNote is storing info in your browser. Until you setup syncing, you are at risk of lousing your notes. To setup syncing. From the home page click `Settings`, then click database. On the right hand side of the panel you will see a Replication url field. This expect a url to your couchDB database in the form of `$protocol://$user:$password@$serverurl:$port/$database`. For example if your server information is as follows: -Item | Value ---- | --- -protocol | http -user | admin -password | password +Item | Value +--------- | --------- +protocol | http +user | admin +password | password serverurl | 127.0.0.1 -port | 5984 -database | opennote +port | 5984 +database | opennote then your replication url would be `http://admin:password@127.0.0.1:6984/opennote` You will see an alert if replication is working. ## Uninstall + If you ever want to shutdown OpenNote run `docker-compose down` in the same folder as `docker-compose.yml`. This will shut down the containers associated with OpenNote. + +## SSL +You can use lets encrypt to get a free valid SSL cert. See https://letsencrypt.org/ and their tool [Cert Bot Tool](https://certbot.eff.org/)