From 979b5eb2a80acfbc049c335647a1c8b3c4dd2122 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Wed, 15 Feb 2017 13:01:19 -0600 Subject: [PATCH] external editor support --- .../app/frontend/controllers/editor.js | 94 +++--- .../app/frontend/models/app/editor.js | 30 ++ .../app/frontend/models/local/itemParams.js | 2 +- .../services/directives/views/editorMenu.js | 72 +++++ .../app/services/filters/startFrom.js | 1 - .../app/services/filters/trusted.js | 5 + .../javascripts/app/services/modelManager.js | 4 +- app/assets/stylesheets/app/_directives.scss | 99 ------- app/assets/stylesheets/app/_extensions.scss | 111 ++++++++ app/assets/stylesheets/app/_header.scss | 142 --------- app/assets/stylesheets/app/_standard.scss | 269 ++++++++++++++++++ app/assets/stylesheets/frontend.css.scss | 3 +- .../directives/contextual-menu.html.haml | 20 +- .../frontend/directives/editor-menu.html.haml | 23 ++ .../templates/frontend/editor.html.haml | 18 +- 15 files changed, 581 insertions(+), 312 deletions(-) create mode 100644 app/assets/javascripts/app/frontend/models/app/editor.js create mode 100644 app/assets/javascripts/app/services/directives/views/editorMenu.js create mode 100644 app/assets/javascripts/app/services/filters/trusted.js delete mode 100644 app/assets/stylesheets/app/_directives.scss create mode 100644 app/assets/stylesheets/app/_extensions.scss create mode 100644 app/assets/stylesheets/app/_standard.scss create mode 100644 app/assets/templates/frontend/directives/editor-menu.html.haml diff --git a/app/assets/javascripts/app/frontend/controllers/editor.js b/app/assets/javascripts/app/frontend/controllers/editor.js index 8aee7ed7f..dae2f43b2 100644 --- a/app/assets/javascripts/app/frontend/controllers/editor.js +++ b/app/assets/javascripts/app/frontend/controllers/editor.js @@ -16,50 +16,9 @@ angular.module('app.frontend') link:function(scope, elem, attrs, ctrl) { - /** - * Insert 4 spaces when a tab key is pressed, - * only used when inside of the text editor. - * If the shift key is pressed first, this event is - * not fired. - */ - var handleTab = function (event) { - if (!event.shiftKey && event.which == 9) { - event.preventDefault(); - var start = this.selectionStart; - var end = this.selectionEnd; - var spaces = " "; - - // Insert 4 spaces - this.value = this.value.substring(0, start) - + spaces + this.value.substring(end); - - // Place cursor 4 spaces away from where - // the tab key was pressed - this.selectionStart = this.selectionEnd = start + 4; - } - } - var handler = function(event) { if (event.ctrlKey || event.metaKey) { switch (String.fromCharCode(event.which).toLowerCase()) { - case 's': - event.preventDefault(); - $timeout(function(){ - ctrl.saveNote(event); - }); - break; - case 'e': - event.preventDefault(); - $timeout(function(){ - ctrl.clickedEditNote(); - }) - break; - case 'm': - event.preventDefault(); - $timeout(function(){ - ctrl.toggleMarkdown(); - }) - break; case 'o': event.preventDefault(); $timeout(function(){ @@ -70,14 +29,6 @@ angular.module('app.frontend') } }; - window.addEventListener('keydown', handler); - var element = document.getElementById("note-text-editor"); - element.addEventListener('keydown', handleTab); - - scope.$on('$destroy', function(){ - window.removeEventListener('keydown', handler); - }) - scope.$watch('ctrl.note', function(note, oldNote){ if(note) { ctrl.setNote(note, oldNote); @@ -88,7 +39,21 @@ angular.module('app.frontend') } } }) - .controller('EditorCtrl', function ($sce, $timeout, authManager, markdownRenderer, $rootScope, extensionManager, syncManager) { + .controller('EditorCtrl', function ($sce, $timeout, authManager, markdownRenderer, $rootScope, extensionManager, syncManager, modelManager) { + + window.addEventListener("message", function(){ + console.log("App received message:", event); + if(event.data.status) { + this.postNoteToExternalEditor(); + } else { + var id = event.data.id; + var text = event.data.text; + if(this.note.uuid == id) { + this.note.text = text; + this.changesMade(); + } + } + }.bind(this), false); this.setNote = function(note, oldNote) { this.editorMode = 'edit'; @@ -96,6 +61,13 @@ angular.module('app.frontend') this.showMenu = false; this.loadTagsString(); + if(note.editorUrl) { + this.customEditor = this.editorForUrl(note.editorUrl); + this.postNoteToExternalEditor(); + } else { + this.customEditor = null; + } + if(note.safeText().length == 0 && note.dummy) { this.focusTitle(100); } @@ -109,6 +81,28 @@ angular.module('app.frontend') } } + this.selectedEditor = function(editor) { + this.showEditorMenu = false; + if(editor.default) { + this.customEditor = null; + } else { + this.customEditor = editor; + } + this.note.editorUrl = editor.url; + }.bind(this) + + this.editorForUrl = function(url) { + var editors = modelManager.itemsForContentType("SN|Editor"); + return editors.filter(function(editor){return editor.url == url})[0]; + } + + this.postNoteToExternalEditor = function() { + var externalEditorElement = document.getElementById("editor-iframe"); + if(externalEditorElement) { + externalEditorElement.contentWindow.postMessage({text: this.note.text, id: this.note.uuid}, '*'); + } + } + this.hasAvailableExtensions = function() { return extensionManager.extensionsInContextOfItem(this.note).length > 0; } diff --git a/app/assets/javascripts/app/frontend/models/app/editor.js b/app/assets/javascripts/app/frontend/models/app/editor.js new file mode 100644 index 000000000..2b823d3a5 --- /dev/null +++ b/app/assets/javascripts/app/frontend/models/app/editor.js @@ -0,0 +1,30 @@ +class Editor extends Item { + + constructor(json_obj) { + super(json_obj); + } + + mapContentToLocalProperties(contentObject) { + super.mapContentToLocalProperties(contentObject) + this.url = contentObject.url; + this.name = contentObject.name; + } + + structureParams() { + var params = { + url: this.url, + name: this.name + }; + + _.merge(params, super.structureParams()); + return params; + } + + toJSON() { + return {uuid: this.uuid} + } + + get content_type() { + return "SN|Editor"; + } +} diff --git a/app/assets/javascripts/app/frontend/models/local/itemParams.js b/app/assets/javascripts/app/frontend/models/local/itemParams.js index 396a51bd1..22d7405ce 100644 --- a/app/assets/javascripts/app/frontend/models/local/itemParams.js +++ b/app/assets/javascripts/app/frontend/models/local/itemParams.js @@ -16,7 +16,7 @@ class ItemParams { } paramsForLocalStorage() { - this.additionalFields = ["updated_at", "dirty"]; + this.additionalFields = ["updated_at", "dirty", "editorUrl"]; this.forExportFile = true; return this.__params(); } diff --git a/app/assets/javascripts/app/services/directives/views/editorMenu.js b/app/assets/javascripts/app/services/directives/views/editorMenu.js new file mode 100644 index 000000000..82d260cb0 --- /dev/null +++ b/app/assets/javascripts/app/services/directives/views/editorMenu.js @@ -0,0 +1,72 @@ +class EditorMenu { + + constructor() { + this.restrict = "E"; + this.templateUrl = "frontend/directives/editor-menu.html"; + this.scope = { + callback: "&", + selectedEditor: "=" + }; + } + + controller($scope, modelManager, extensionManager, 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.selectEditor = function(editor) { + $scope.callback()(editor); + } + + $scope.deleteEditor = function(editor) { + if(confirm("Are you sure you want to delete this editor?")) { + modelManager.setItemToBeDeleted(editor); + syncManager.sync(); + } + } + + $scope.submitNewEditorRequest = function() { + var editor = createEditor($scope.formData.url); + modelManager.addItem(editor); + editor.setDirty(true); + syncManager.sync(); + $scope.editors.push(editor); + $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, " ")); + } + } + +} + +angular.module('app.frontend').directive('editorMenu', () => new EditorMenu); diff --git a/app/assets/javascripts/app/services/filters/startFrom.js b/app/assets/javascripts/app/services/filters/startFrom.js index 2ebd72e42..3cf824c4c 100644 --- a/app/assets/javascripts/app/services/filters/startFrom.js +++ b/app/assets/javascripts/app/services/filters/startFrom.js @@ -1,4 +1,3 @@ -// Start from filter angular.module('app.frontend').filter('startFrom', function() { return function(input, start) { return input.slice(start); diff --git a/app/assets/javascripts/app/services/filters/trusted.js b/app/assets/javascripts/app/services/filters/trusted.js new file mode 100644 index 000000000..7bb57b301 --- /dev/null +++ b/app/assets/javascripts/app/services/filters/trusted.js @@ -0,0 +1,5 @@ +angular.module('app.frontend').filter('trusted', ['$sce', function ($sce) { + return function(url) { + return $sce.trustAsResourceUrl(url); + }; +}]); diff --git a/app/assets/javascripts/app/services/modelManager.js b/app/assets/javascripts/app/services/modelManager.js index ab8ca7f44..9a26cfa14 100644 --- a/app/assets/javascripts/app/services/modelManager.js +++ b/app/assets/javascripts/app/services/modelManager.js @@ -8,7 +8,7 @@ class ModelManager { this.itemChangeObservers = []; this.items = []; this._extensions = []; - this.acceptableContentTypes = ["Note", "Tag", "Extension"]; + this.acceptableContentTypes = ["Note", "Tag", "Extension", "SN|Editor"]; } get allItems() { @@ -121,6 +121,8 @@ class ModelManager { item = new Tag(json_obj); } else if(json_obj.content_type == "Extension") { item = new Extension(json_obj); + } else if(json_obj.content_type == "SN|Editor") { + item = new Editor(json_obj); } else { item = new Item(json_obj); } diff --git a/app/assets/stylesheets/app/_directives.scss b/app/assets/stylesheets/app/_directives.scss deleted file mode 100644 index 8d5f28cc5..000000000 --- a/app/assets/stylesheets/app/_directives.scss +++ /dev/null @@ -1,99 +0,0 @@ -.extension-render-modal { - position: fixed; - margin-left: auto; - margin-right: auto; - left: 0; - right: 0; - top: 0; - bottom: 0; - z-index: 10000; - width: 100vw; - height: 100vh; - background-color: rgba(gray, 0.3); - - .content { - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); - background-color: white; - width: 700px; - height: 500px; - margin: auto; - padding: 25px; - position: absolute; - top: 0; left: 0; bottom: 0; right: 0; - overflow-y: scroll; - } -} - -.dropdown-menu.contextual-menu { - overflow-y: scroll; - max-height: 85vh; - - .extension { - - &:not(:first-child) { - margin-top: 18px; - } - - .ext-header { - background-color: #ededed; - border-bottom: 1px solid #d3d3d3; - padding-top: 12px; - padding-left: 10px; - padding-bottom: 10px; - position: relative; - - > .name { - font-size: 14px; - } - - > .access { - font-size: 12px; - opacity: 0.5; - font-weight: normal; - margin-top: 2px; - } - - > .loading { - position: absolute; - height: 15px; - width: 15px; - right: 10px; - top: 20px; - } - } - - ul { - margin-top: 0px; - margin-bottom: 0px; - list-style:none; - padding-left:0; - - li { - cursor: pointer; - height: auto; - - &.action { - padding: 10px; - border-bottom: 1px solid rgba(black, 0.1); - background-color: rgba(white, 0.9); - - &:hover { - background-color: rgba(gray, 0.05); - } - - > .name { - font-weight: bold; - font-size: 14px; - } - - > .desc { - font-weight: normal; - opacity: 0.5; - margin-top: 1px; - font-size: 12px; - } - } - } - } - } -} diff --git a/app/assets/stylesheets/app/_extensions.scss b/app/assets/stylesheets/app/_extensions.scss new file mode 100644 index 000000000..1958abff2 --- /dev/null +++ b/app/assets/stylesheets/app/_extensions.scss @@ -0,0 +1,111 @@ +.extension-render-modal { + position: fixed; + margin-left: auto; + margin-right: auto; + left: 0; + right: 0; + top: 0; + bottom: 0; + z-index: 10000; + width: 100vw; + height: 100vh; + background-color: rgba(gray, 0.3); + + .content { + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-color: white; + width: 700px; + height: 500px; + margin: auto; + padding: 25px; + position: absolute; + top: 0; left: 0; bottom: 0; right: 0; + overflow-y: scroll; + } +} + +.menu-section-footer { + background-color: #ededed; + border-top: 1px solid #d3d3d3; + position: relative; + padding: 10px; +} + +.menu-section-header { + background-color: #ededed; + border-bottom: 1px solid #d3d3d3; + position: relative; + padding-top: 12px; + padding-left: 10px; + padding-bottom: 10px; + + + > .title { + font-size: 14px; + } + + > .subtitle { + font-size: 12px; + opacity: 0.5; + font-weight: normal; + margin-top: 2px; + } + + > .loading { + position: absolute; + height: 15px; + width: 15px; + right: 10px; + top: 20px; + } +} + +.dropdown-menu.editor-menu { + overflow-y: scroll; + max-height: 85vh; + + &:not(:first-child) { + margin-top: 18px; + } + + ul { + margin-top: 0px; + margin-bottom: 0px; + list-style:none; + padding-left:0; + + li { + cursor: pointer; + height: auto; + + &.menu-item { + padding: 10px; + border-bottom: 1px solid rgba(black, 0.1); + background-color: rgba(white, 0.9); + + &:hover { + background-color: rgba(gray, 0.05); + } + + &.nonactive { + cursor: default; + &:hover { + background-color: rgba(white, 0.9) !important; + } + } + + .menu-item-title { + font-weight: bold; + font-size: 14px; + } + + .menu-item-subtitle { + font-weight: normal; + opacity: 0.5; + margin-top: 1px; + font-size: 12px; + } + } + } + } +} diff --git a/app/assets/stylesheets/app/_header.scss b/app/assets/stylesheets/app/_header.scss index 1df8ef09a..fdeb83a11 100644 --- a/app/assets/stylesheets/app/_header.scss +++ b/app/assets/stylesheets/app/_header.scss @@ -1,145 +1,3 @@ -.pull-left { - float: left !important; -} - -.pull-right { - float: right !important; -} - -.mt-1 { - margin-top: 1px !important; -} - -.mt-2 { - margin-top: 2px !important; -} - -.mt-5 { - margin-top: 5px !important; -} - -.mt-10 { - margin-top: 10px !important; -} - -.mt-15 { - margin-top: 15px !important; -} - -.mt-25 { - margin-top: 25px !important; -} - -.mb-0 { - margin-bottom: 0px !important; -} - -.mb-5 { - margin-bottom: 5px !important; -} - -.mb-10 { - margin-bottom: 10px !important; -} - -.mr-5 { - margin-right: 5px; -} - -.faded { - opacity: 0.5; -} - -.center-align { - text-align: center !important; -} - -.center { - margin-left: auto !important; - margin-right: auto !important; -} - -.block { - display: block !important; -} - -.wrap { - word-wrap: break-word; -} - -.one-line-overflow { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} - -.small-v-space { - height: 6px; - display: block; -} - -.medium-v-space { - height: 12px; - display: block; -} - -.large-v-space { - height: 24px; - display: block; -} - -.small-padding { - padding: 5px !important; -} - -.medium-padding { - padding: 10px !important; -} - -.pb-4 { - padding-bottom: 4px !important; -} - -.pb-6 { - padding-bottom: 6px !important; -} - -.pb-10 { - padding-bottom: 10px !important; -} - -.large-padding { - padding: 22px !important; -} - -.red { - color: red !important; -} - -.blue { - color: $blue-color; -} - -.bold { - font-weight: bold !important; -} - -.italic { - font-style: italic !important; -} - -.normal { - font-weight: normal !important; -} - -.small { - font-size: 10px !important; -} - -.inline { - display: inline-block; -} - .fake-link { font-weight: bold; cursor: pointer; diff --git a/app/assets/stylesheets/app/_standard.scss b/app/assets/stylesheets/app/_standard.scss new file mode 100644 index 000000000..bf5e098b1 --- /dev/null +++ b/app/assets/stylesheets/app/_standard.scss @@ -0,0 +1,269 @@ +.pull-left { + float: left !important; +} + +.pull-right { + float: right !important; +} + +.mt-1 { + margin-top: 1px !important; +} + +.mt-2 { + margin-top: 2px !important; +} + +.mt-5 { + margin-top: 5px !important; +} + +.mt-10 { + margin-top: 10px !important; +} + +.mt-15 { + margin-top: 15px !important; +} + +.mt-20 { + margin-top: 20px !important; +} + +.mt-25 { + margin-top: 25px !important; +} + +.mt-50 { + margin-top: 50px !important; +} + +.mt-100 { + margin-top: 100px !important; +} + +.mb-0 { + margin-bottom: 0px !important; +} + +.mb-5 { + margin-bottom: 5px !important; +} + +.mb-10 { + margin-bottom: 10px !important; +} + +.mr-5 { + margin-right: 5px; +} + +.mr-10 { + margin-right: 10px; +} + +.mr-20 { + margin-right: 20px; +} + +.pb-0 { + padding-bottom: 0px !important; +} + +.faded { + opacity: 0.5; +} + +.center-align { + text-align: center !important; +} + +.center { + margin-left: auto !important; + margin-right: auto !important; +} + +.block { + display: block !important; +} + +.wrap { + word-wrap: break-word; +} + +.one-line-overflow { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.small-v-space { + height: 6px; + display: block; +} + +.medium-v-space { + height: 12px; + display: block; +} + +.large-v-space { + height: 24px; + display: block; +} + +.small-padding { + padding: 5px !important; +} + +.medium-padding { + padding: 10px !important; +} + +.pb-4 { + padding-bottom: 4px !important; +} + +.pb-6 { + padding-bottom: 6px !important; +} + +.pb-10 { + padding-bottom: 10px !important; +} + +.large-padding { + padding: 22px !important; +} + +.red { + color: red !important; +} + +.bold { + font-weight: bold !important; +} + +.normal { + font-weight: normal !important; +} + +.small { + font-size: 10px !important; +} + +.medium { + font-size: 14px !important; +} + +.inline { + display: inline-block; + + &.top { + vertical-align: top; + } + + &.middle { + vertical-align: middle; + } +} + +button { + cursor: pointer; +} + +input.form-control { + margin-bottom: 10px; + border-radius: 0px; + min-height: 39px; + font-size: 14px; + padding-left: 6px; +} + +button { + border: none; + + @mixin wide-button() { + font-weight: bold; + text-align: center; + padding: 10px; + font-size: 16px; + // min-width: 200px; + + &:hover { + text-decoration: underline; + } + } + + &.black { + @include wide-button(); + background-color: black; + color: white; + } + + &.white { + @include wide-button(); + background-color: white; + color: black; + border: 1px solid rgba(gray, 0.2); + } +} + + +.gray-bg { + background-color: #f6f6f6; + border: 1px solid #f2f2f2; +} + +.white-bg { + background-color: white; + border: 1px solid rgba(gray, 0.2); +} + +.col-container { + // white-space: nowrap; +} + +@mixin col() { + display: inline-block; + vertical-align: top; + white-space: normal; +} + +.col-10 { + width: 10%; + @include col(); +} + +.col-15 { + width: 15%; + @include col(); +} + +.col-20 { + width: 20%; + @include col(); +} + +.col-45 { + width: 45%; + @include col(); +} + +.col-50 { + width: 50%; + @include col(); +} + +.col-80 { + width: 80%; + @include col(); +} + +.relative { + position: relative !important; +} + +.absolute { + position: absolute !important; +} diff --git a/app/assets/stylesheets/frontend.css.scss b/app/assets/stylesheets/frontend.css.scss index bfe290297..026702b13 100644 --- a/app/assets/stylesheets/frontend.css.scss +++ b/app/assets/stylesheets/frontend.css.scss @@ -1,5 +1,6 @@ $dark-gray: #2e2e2e; +@import "app/standard"; @import "app/mostrap"; @import "app/main"; @import "app/common"; @@ -7,7 +8,7 @@ $dark-gray: #2e2e2e; @import "app/tags"; @import "app/notes"; @import "app/editor"; -@import "app/directives"; +@import "app/extensions"; @font-face { font-family: 'icomoon'; diff --git a/app/assets/templates/frontend/directives/contextual-menu.html.haml b/app/assets/templates/frontend/directives/contextual-menu.html.haml index 725b56474..6fbfaa9aa 100644 --- a/app/assets/templates/frontend/directives/contextual-menu.html.haml +++ b/app/assets/templates/frontend/directives/contextual-menu.html.haml @@ -1,21 +1,21 @@ -%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark.contextual-menu +%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark.editor-menu .extension{"ng-repeat" => "extension in extensions"} - .ext-header - .name {{extension.name}} - .access + .menu-section-header + .title {{extension.name}} + .subtitle Can access your data %strong {{accessTypeForExtension(extension)}} .spinner.loading{"ng-if" => "extension.loading"} %ul - %li.action{"ng-repeat" => "action in extension.actionsWithContextForItem(item)", "ng-click" => "executeAction(action, extension)"} - .name {{action.label}} - .desc {{action.desc}} + %li.menu-item{"ng-repeat" => "action in extension.actionsWithContextForItem(item)", "ng-click" => "executeAction(action, extension)"} + .menu-item-title {{action.label}} + .menu-item-subtitle {{action.desc}} %div{"ng-if" => "action.showNestedActions"} %ul.mt-10 - %li.action.white-bg{"ng-repeat" => "subaction in action.subactions", "ng-click" => "executeAction(subaction, extension); $event.stopPropagation()", "style" => "margin-top: -1px;"} - .name {{subaction.label}} - .desc {{subaction.desc}} + %li.menu-item.white-bg{"ng-repeat" => "subaction in action.subactions", "ng-click" => "executeAction(subaction, extension); $event.stopPropagation()", "style" => "margin-top: -1px;"} + .menu-item-title {{subaction.label}} + .menu-item-subtitle {{subaction.desc}} %span{"ng-if" => "subaction.running"} .spinner{"style" => "margin-top: 3px;"} diff --git a/app/assets/templates/frontend/directives/editor-menu.html.haml b/app/assets/templates/frontend/directives/editor-menu.html.haml new file mode 100644 index 000000000..f7509a45c --- /dev/null +++ b/app/assets/templates/frontend/directives/editor-menu.html.haml @@ -0,0 +1,23 @@ +%ul.dropdown-menu.dropdown-menu-left.nt-dropdown-menu.dark.editor-menu + .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"} ✓ + .menu-item-title.pull-left {{editor.name}} + + %div{"ng-if" => "editors.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"} ✓ + .pull-left{"style" => "width: 60%"} + .menu-item-title {{editor.name}} + .menu-item-subtitle.wrap {{editor.url}} + .pull-right + %button.white.medium.inline.top{"style" => "width: 50px; height: 40px;", "ng-click" => "deleteEditor(editor); $event.stopPropagation();"} ☓ + .menu-section-footer.mt-10 + %input.form-control{"ng-model" => "formData.url", "placeholder" => "Add new editor via URL", "ng-keyup" => "$event.keyCode == 13 && submitNewEditorRequest()"} + %a.block{"href" => ""} Available Editors diff --git a/app/assets/templates/frontend/editor.html.haml b/app/assets/templates/frontend/editor.html.haml index 7b5242531..24d719660 100644 --- a/app/assets/templates/frontend/editor.html.haml +++ b/app/assets/templates/frontend/editor.html.haml @@ -26,6 +26,15 @@ .shortcut Cmd + M %li{"ng-click" => "ctrl.deleteNote()"} .text Delete + + %li.sep + %li.dropdown{"click-outside" => "ctrl.showEditorMenu = false;", "is-open" => "ctrl.showEditorMenu"} + %a.dropdown-toggle{"ng-click" => "ctrl.showEditorMenu = !ctrl.showEditorMenu; ctrl.showMenu = false;"} + Editor + %span.caret + %span.sr-only + %editor-menu{"ng-if" => "ctrl.showEditorMenu", "callback" => "ctrl.selectedEditor", "selected-editor" => "ctrl.customEditor"} + %li.sep %li.dropdown{"ng-if" => "ctrl.hasAvailableExtensions()", "click-outside" => "ctrl.showExtensions = false;", "is-open" => "ctrl.showExtensions"} %a.dropdown-toggle{"ng-click" => "ctrl.showExtensions = !ctrl.showExtensions; ctrl.showMenu = false;"} @@ -34,13 +43,8 @@ %span.sr-only %contextual-extensions-menu{"ng-if" => "ctrl.showExtensions", "item" => "ctrl.note"} - .markdown.icon{"ng-if" => "ctrl.editorMode == 'preview'", "ng-click" => "ctrl.showMarkdown = !ctrl.showMarkdown"} - .icon-markdown - .panel.panel-default.info-panel{"ng-if" => "ctrl.showMarkdown"} - .panel-body{"style" => "text-align: center; color: black;"} - This editor is Markdown enabled. - .editor-content{"ng-class" => "{'fullscreen' : ctrl.fullscreen }"} - %textarea.editable#note-text-editor{"ng-class" => "{'fullscreen' : ctrl.fullscreen }", "ng-show" => "ctrl.editorMode == 'edit'", "ng-model" => "ctrl.note.text", + %iframe#editor-iframe{"ng-if" => "ctrl.customEditor", "ng-src" => "{{ctrl.customEditor.url | trusted}}", "frameBorder" => "0", "style" => "width: 100%; height: 100%; z-index: 1000; float: left;"} + %textarea.editable#note-text-editor{"ng-if" => "!ctrl.customEditor", "ng-class" => "{'fullscreen' : ctrl.fullscreen }", "ng-show" => "ctrl.editorMode == 'edit'", "ng-model" => "ctrl.note.text", "ng-change" => "ctrl.contentChanged()", "ng-click" => "ctrl.clickedTextArea()", "ng-focus" => "ctrl.onContentFocus()"} .preview{"ng-class" => "{'fullscreen' : ctrl.fullscreen }", "ng-if" => "ctrl.editorMode == 'preview'", "ng-bind-html" => "ctrl.renderedContent()", "ng-dblclick" => "ctrl.onPreviewDoubleClick()"}