From 5a98d44681155aa603ef625567f7bf21b6beb481 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Sat, 15 Apr 2017 11:10:59 -0500 Subject: [PATCH] default editors --- .../app/frontend/controllers/editor.js | 36 +++--- .../app/frontend/models/app/editor.js | 6 +- .../services/directives/views/editorMenu.js | 52 ++------- .../javascripts/app/services/editorManager.js | 107 ++++++++++++++++++ .../javascripts/app/services/syncManager.js | 1 + app/assets/stylesheets/app/_common.scss | 6 +- app/assets/stylesheets/app/_extensions.scss | 1 + .../frontend/directives/editor-menu.html.haml | 16 ++- .../templates/frontend/editor.html.haml | 6 +- 9 files changed, 157 insertions(+), 74 deletions(-) create mode 100644 app/assets/javascripts/app/services/editorManager.js diff --git a/app/assets/javascripts/app/frontend/controllers/editor.js b/app/assets/javascripts/app/frontend/controllers/editor.js index 4f5e67417..ff02c8ffa 100644 --- a/app/assets/javascripts/app/frontend/controllers/editor.js +++ b/app/assets/javascripts/app/frontend/controllers/editor.js @@ -23,7 +23,7 @@ angular.module('app.frontend') } } }) - .controller('EditorCtrl', function ($sce, $timeout, authManager, $rootScope, extensionManager, syncManager, modelManager) { + .controller('EditorCtrl', function ($sce, $timeout, authManager, $rootScope, extensionManager, syncManager, modelManager, editorManager) { window.addEventListener("message", function(event){ if(event.data.status) { @@ -36,9 +36,9 @@ angular.module('app.frontend') if(this.note.uuid === id) { this.note.text = text; if(data) { - var changesMade = this.customEditor.setData(id, data); + var changesMade = this.editor.setData(id, data); if(changesMade) { - this.customEditor.setDirty(true); + this.editor.setDirty(true); } } this.changesMade(); @@ -52,14 +52,14 @@ angular.module('app.frontend') this.setNote = function(note, oldNote) { this.noteReady = false; - var currentEditor = this.customEditor; - this.customEditor = null; + var currentEditor = this.editor; + this.editor = null; this.showExtensions = false; this.showMenu = false; this.loadTagsString(); var setEditor = function(editor) { - this.customEditor = editor; + this.editor = editor; this.postNoteToExternalEditor(); this.noteReady = true; }.bind(this) @@ -76,10 +76,11 @@ angular.module('app.frontend') setEditor(editor); } } else { - this.customEditor = null; + this.editor = null; this.noteReady = true; } + if(note.safeText().length == 0 && note.dummy) { this.focusTitle(100); } @@ -96,18 +97,15 @@ angular.module('app.frontend') this.selectedEditor = function(editor) { this.showEditorMenu = false; - if(this.customEditor && editor !== this.customEditor) { - this.customEditor.removeItemAsRelationship(this.note); - this.customEditor.setDirty(true); + if(this.editor && editor !== this.editor) { + this.editor.removeItemAsRelationship(this.note); + this.editor.setDirty(true); } - if(editor.default) { - this.customEditor = null; - } else { - this.customEditor = editor; - this.customEditor.addItemAsRelationship(this.note); - this.customEditor.setDirty(true); - } + editor.addItemAsRelationship(this.note); + editor.setDirty(true); + + this.editor = editor; }.bind(this) this.editorForNote = function(note) { @@ -117,13 +115,13 @@ angular.module('app.frontend') return editor; } } - return null; + return _.find(editors, {default: true}); } this.postNoteToExternalEditor = function() { var externalEditorElement = document.getElementById("editor-iframe"); if(externalEditorElement) { - externalEditorElement.contentWindow.postMessage({text: this.note.text, data: this.customEditor.dataForKey(this.note.uuid), id: this.note.uuid}, '*'); + externalEditorElement.contentWindow.postMessage({text: this.note.text, data: this.editor.dataForKey(this.note.uuid), id: this.note.uuid}, '*'); } } diff --git a/app/assets/javascripts/app/frontend/models/app/editor.js b/app/assets/javascripts/app/frontend/models/app/editor.js index 00a09cc0f..74fc06868 100644 --- a/app/assets/javascripts/app/frontend/models/app/editor.js +++ b/app/assets/javascripts/app/frontend/models/app/editor.js @@ -15,13 +15,17 @@ class Editor extends Item { this.url = contentObject.url; this.name = contentObject.name; this.data = contentObject.data || {}; + this.default = contentObject.default; + this.systemEditor = contentObject.systemEditor; } structureParams() { var params = { url: this.url, name: this.name, - data: this.data + data: this.data, + default: this.default, + systemEditor: this.systemEditor }; _.merge(params, super.structureParams()); diff --git a/app/assets/javascripts/app/services/directives/views/editorMenu.js b/app/assets/javascripts/app/services/directives/views/editorMenu.js index 63aab1e70..300d0903f 100644 --- a/app/assets/javascripts/app/services/directives/views/editorMenu.js +++ b/app/assets/javascripts/app/services/directives/views/editorMenu.js @@ -9,24 +9,11 @@ class EditorMenu { }; } - controller($scope, modelManager, extensionManager, syncManager) { + controller($scope, modelManager, editorManager, syncManager) { 'ngInject'; $scope.formData = {}; - - let editorContentType = "SN|Editor"; - - let defaultEditor = { - default: true, - name: "Plain" - } - - $scope.sysEditors = [defaultEditor]; - $scope.editors = modelManager.itemsForContentType(editorContentType); - - $scope.editorForUrl = function(url) { - return $scope.editors.filter(function(editor){return editor.url == url})[0]; - } + $scope.editorManager = editorManager; $scope.selectEditor = function(editor) { $scope.callback()(editor); @@ -34,38 +21,23 @@ class EditorMenu { $scope.deleteEditor = function(editor) { if(confirm("Are you sure you want to delete this editor?")) { - modelManager.setItemToBeDeleted(editor); - syncManager.sync(); - _.pull($scope.editors, editor); + editorManager.deleteEditor(editor); } } + $scope.setDefaultEditor = function(editor) { + editorManager.setDefaultEditor(editor); + } + + $scope.removeDefaultEditor = function(editor) { + editorManager.removeDefaultEditor(editor); + } + $scope.submitNewEditorRequest = function() { - var editor = createEditor($scope.formData.url); - modelManager.addItem(editor); - editor.setDirty(true); - syncManager.sync(); - $scope.editors.push(editor); + editorManager.addNewEditorFromURL($scope.formData.url); $scope.formData = {}; } - function createEditor(url) { - var name = getParameterByName("name", url); - return modelManager.createItem({ - content_type: editorContentType, - url: url, - name: name - }) - } - - function getParameterByName(name, url) { - name = name.replace(/[\[\]]/g, "\\$&"); - var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), - results = regex.exec(url); - if (!results) return null; - if (!results[2]) return ''; - return decodeURIComponent(results[2].replace(/\+/g, " ")); - } } } diff --git a/app/assets/javascripts/app/services/editorManager.js b/app/assets/javascripts/app/services/editorManager.js new file mode 100644 index 000000000..2ea973f13 --- /dev/null +++ b/app/assets/javascripts/app/services/editorManager.js @@ -0,0 +1,107 @@ +class EditorManager { + + + constructor($rootScope, modelManager, syncManager) { + this.syncManager = syncManager; + this.modelManager = modelManager; + + this.editorType = "SN|Editor"; + this._systemEditor = { + systemEditor: true, + name: "Plain" + } + + $rootScope.$on("sync:completed", function(){ + if(this.systemEditor.uuid) { + return; + } + + var liveSysEditor = _.find(this.allEditors, {systemEditor: true}); + if(liveSysEditor) { + this._systemEditor = liveSysEditor; + } else { + this._systemEditor = modelManager.createItem({ + content_type: this.editorType, + systemEditor: true, + name: "Plain" + }) + modelManager.addItem(this._systemEditor); + this._systemEditor.setDirty(true); + syncManager.sync(); + } + }.bind(this)) + } + + get allEditors() { + return this.modelManager.itemsForContentType(this.editorType); + } + + get externalEditors() { + return this.allEditors.filter(function(editor){ + return !editor.systemEditor; + }) + } + + get systemEditors() { + return [this.systemEditor]; + } + + get systemEditor() { + return this._systemEditor; + } + + get defaultEditor() { + return _.find(this.externalEditors, {default: true}); + } + + editorForUrl(url) { + return this.externalEditors.filter(function(editor){return editor.url == url})[0]; + } + + setDefaultEditor(editor) { + var defaultEditor = this.defaultEditor; + if(defaultEditor) { + defaultEditor.default = false; + defaultEditor.setDirty(true); + } + editor.default = true; + editor.setDirty(true); + this.syncManager.sync(); + } + + removeDefaultEditor(editor) { + editor.default = false; + editor.setDirty(true); + this.syncManager.sync(); + } + + addNewEditorFromURL(url) { + var name = getParameterByName("name", url); + var editor = modelManager.createItem({ + content_type: this.editorType, + url: url, + name: name + }) + + this.modelManager.addItem(editor); + editor.setDirty(true); + this.syncManager.sync(); + } + + deleteEditor(editor) { + this.modelManager.setItemToBeDeleted(editor); + this.syncManager.sync(); + } + + getParameterByName(name, url) { + name = name.replace(/[\[\]]/g, "\\$&"); + var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), + results = regex.exec(url); + if (!results) return null; + if (!results[2]) return ''; + return decodeURIComponent(results[2].replace(/\+/g, " ")); + } + +} + +angular.module('app.frontend').service('editorManager', EditorManager); diff --git a/app/assets/javascripts/app/services/syncManager.js b/app/assets/javascripts/app/services/syncManager.js index 1ea34caf3..81f70a87a 100644 --- a/app/assets/javascripts/app/services/syncManager.js +++ b/app/assets/javascripts/app/services/syncManager.js @@ -208,6 +208,7 @@ class SyncManager { }.bind(this), 10); // wait 10ms to allow UI to update } else { this.callQueuedCallbacksAndCurrent(callback, response); + this.$rootScope.$broadcast("sync:completed"); } }.bind(this); diff --git a/app/assets/stylesheets/app/_common.scss b/app/assets/stylesheets/app/_common.scss index 87f8bbdb0..c7c91c143 100644 --- a/app/assets/stylesheets/app/_common.scss +++ b/app/assets/stylesheets/app/_common.scss @@ -37,14 +37,10 @@ &:hover { background-color: #f5f5f5; color: black; - a { - color: black !important; - } } a { - color: $selected-text-color !important; height: 100%; - font-weight: bold !important; + font-weight: bold; } .text { color: $selected-text-color; diff --git a/app/assets/stylesheets/app/_extensions.scss b/app/assets/stylesheets/app/_extensions.scss index c5cf82fd2..a1e138eb4 100644 --- a/app/assets/stylesheets/app/_extensions.scss +++ b/app/assets/stylesheets/app/_extensions.scss @@ -98,6 +98,7 @@ .menu-item-title { font-weight: bold; font-size: 14px; + margin-bottom: 3px; } .menu-item-subtitle { diff --git a/app/assets/templates/frontend/directives/editor-menu.html.haml b/app/assets/templates/frontend/directives/editor-menu.html.haml index 374e58918..fed6e6f9d 100644 --- a/app/assets/templates/frontend/directives/editor-menu.html.haml +++ b/app/assets/templates/frontend/directives/editor-menu.html.haml @@ -2,20 +2,24 @@ .menu-section-header .title System Editors %ul - %li.menu-item{"ng-repeat" => "editor in sysEditors", "ng-click" => "selectEditor(editor)"} - %span.pull-left.mr-10{"ng-if" => "!selectedEditor"} ✓ + %li.menu-item{"ng-repeat" => "editor in editorManager.systemEditors", "ng-click" => "selectEditor(editor)"} + %span.pull-left.mr-10{"ng-if" => "selectedEditor === editor"} ✓ .menu-item-title.pull-left {{editor.name}} - %div{"ng-if" => "editors.length > 0"} + %div{"ng-if" => "editorManager.externalEditors.length > 0"} .menu-section-header .title External Editors .subtitle Can access your current note decrypted. %ul - %li.menu-item{"ng-repeat" => "editor in editors", "ng-click" => "selectEditor(editor)"} - %span.pull-left.mr-10{"ng-if" => "selectedEditor == editor"} ✓ + %li.menu-item{"ng-repeat" => "editor in editorManager.externalEditors", "ng-click" => "selectEditor(editor)"} + .pull-left{"style" => "width: 60%"} .menu-item-title {{editor.name}} - .menu-item-subtitle.wrap {{editor.url}} + %a.faded{"ng-if" => "!editor.default", "ng-click" => "setDefaultEditor(editor); $event.stopPropagation();"} Set Default + %a.red{"ng-if" => "editor.default", "ng-click" => "removeDefaultEditor(editor); $event.stopPropagation();"} Remove Default + %a.faded{"ng-click" => "editor.showUrl = !editor.showUrl; $event.stopPropagation();"} Show URL + .menu-item-subtitle.wrap{"ng-if" => "editor.showUrl"} {{editor.url}} + %span.pull-left.ml-10{"ng-if" => "selectedEditor === editor"} ✓ .pull-right %button.white.medium.inline.top{"style" => "width: 50px; height: 40px;", "ng-click" => "deleteEditor(editor); $event.stopPropagation();"} ☓ .menu-section-footer.mt-10 diff --git a/app/assets/templates/frontend/editor.html.haml b/app/assets/templates/frontend/editor.html.haml index 082d5596a..42ec42fc9 100644 --- a/app/assets/templates/frontend/editor.html.haml +++ b/app/assets/templates/frontend/editor.html.haml @@ -28,7 +28,7 @@ Editor %span.caret %span.sr-only - %editor-menu{"ng-if" => "ctrl.showEditorMenu", "callback" => "ctrl.selectedEditor", "selected-editor" => "ctrl.customEditor"} + %editor-menu{"ng-if" => "ctrl.showEditorMenu", "callback" => "ctrl.selectedEditor", "selected-editor" => "ctrl.editor"} %li.sep %li.dropdown.pull-left{"ng-if" => "ctrl.hasAvailableExtensions()", "click-outside" => "ctrl.showExtensions = false;", "is-open" => "ctrl.showExtensions"} @@ -39,6 +39,6 @@ %contextual-extensions-menu{"ng-if" => "ctrl.showExtensions", "item" => "ctrl.note"} .editor-content{"ng-if" => "ctrl.noteReady", "ng-class" => "{'fullscreen' : ctrl.fullscreen }"} - %iframe#editor-iframe{"ng-if" => "ctrl.customEditor", "ng-src" => "{{ctrl.customEditor.url | trusted}}", "frameBorder" => "0", "style" => "width: 100%;"} - %textarea.editable#note-text-editor{"ng-if" => "!ctrl.customEditor", "ng-class" => "{'fullscreen' : ctrl.fullscreen }", "ng-model" => "ctrl.note.text", + %iframe#editor-iframe{"ng-if" => "ctrl.editor && !ctrl.editor.systemEditor", "ng-src" => "{{ctrl.editor.url | trusted}}", "frameBorder" => "0", "style" => "width: 100%;"} + %textarea.editable#note-text-editor{"ng-if" => "!ctrl.editor || ctrl.editor.systemEditor", "ng-class" => "{'fullscreen' : ctrl.fullscreen }", "ng-model" => "ctrl.note.text", "ng-change" => "ctrl.contentChanged()", "ng-click" => "ctrl.clickedTextArea()", "ng-focus" => "ctrl.onContentFocus()"}