From 6ca6758995f0254e142d9d06bcf54bc944148218 Mon Sep 17 00:00:00 2001 From: Matthew Harrison-Jones Date: Mon, 12 Aug 2013 14:12:39 +0100 Subject: [PATCH 1/3] Bug Fix: Corrected wrong Keyboard Shortcuts in help modal --- core/client/tpl/modals/markdown.hbs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/client/tpl/modals/markdown.hbs b/core/client/tpl/modals/markdown.hbs index ed631eb64f..612e4039df 100644 --- a/core/client/tpl/modals/markdown.hbs +++ b/core/client/tpl/modals/markdown.hbs @@ -50,37 +50,37 @@ H1 # Heading - Alt + 1 + Ctrl + Alt + 1 H2 ## Heading - Alt + 2 + Ctrl + Alt + 2 H3 ### Heading - Alt + 3 + Ctrl + Alt + 3 H4 #### Heading - Alt + 4 + Ctrl + Alt + 4 H5 ##### Heading - Alt + 5 + Ctrl + Alt + 5 H6 ###### Heading - Alt + 6 + Ctrl + Alt + 6 Select Word - Ctrl + Option + W + Ctrl + Alt + W Uppercase @@ -95,7 +95,7 @@ Titlecase - Ctrl + Option + Shift + U + Ctrl + Alt + Shift + U Insert Current Date From 28937f942627e55e18f760d40070a9454b11e876 Mon Sep 17 00:00:00 2001 From: Matthew Harrison-Jones Date: Mon, 12 Aug 2013 14:58:01 +0100 Subject: [PATCH 2/3] Improved several keyboard shortcuts behaviour to more closely match Mou These include Headings, Lists and inserted dates --- core/client/markdown-actions.js | 60 +++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/core/client/markdown-actions.js b/core/client/markdown-actions.js index d87c3a4af2..3823024109 100644 --- a/core/client/markdown-actions.js +++ b/core/client/markdown-actions.js @@ -1,6 +1,6 @@ // # Surrounds given text with Markdown syntax -/*global $, window, CodeMirror, Showdown */ +/*global $, window, CodeMirror, Showdown, moment */ (function () { "use strict"; var Markdown = { @@ -15,8 +15,50 @@ self.replace(); }, replace: function () { - var text = this.elem.getSelection(), pass = true, md, cursor, word, converter; + var text = this.elem.getSelection(), pass = true, md, cursor, line, word, converter; switch (this.style) { + case "h1": + cursor = this.elem.getCursor(); + line = this.elem.getLine(cursor.line); + this.elem.setLine(cursor.line, "# " + line); + this.elem.setCursor(cursor.line, cursor.ch + 2); + pass = false; + break; + case "h2": + cursor = this.elem.getCursor(); + line = this.elem.getLine(cursor.line); + this.elem.setLine(cursor.line, "## " + line); + this.elem.setCursor(cursor.line, cursor.ch + 3); + pass = false; + break; + case "h3": + cursor = this.elem.getCursor(); + line = this.elem.getLine(cursor.line); + this.elem.setLine(cursor.line, "### " + line); + this.elem.setCursor(cursor.line, cursor.ch + 4); + pass = false; + break; + case "h4": + cursor = this.elem.getCursor(); + line = this.elem.getLine(cursor.line); + this.elem.setLine(cursor.line, "#### " + line); + this.elem.setCursor(cursor.line, cursor.ch + 5); + pass = false; + break; + case "h5": + cursor = this.elem.getCursor(); + line = this.elem.getLine(cursor.line); + this.elem.setLine(cursor.line, "##### " + line); + this.elem.setCursor(cursor.line, cursor.ch + 6); + pass = false; + break; + case "h6": + cursor = this.elem.getCursor(); + line = this.elem.getLine(cursor.line); + this.elem.setLine(cursor.line, "###### " + line); + this.elem.setCursor(cursor.line, cursor.ch + 7); + pass = false; + break; case "link": md = this.options.syntax.link.replace('$1', text); this.elem.replaceSelection(md, "end"); @@ -58,9 +100,12 @@ break; case "list": md = text.replace(/^/gm, "* "); - this.elem.replaceSelection("\n" + md + "\n", "end"); + this.elem.replaceSelection(md, "end"); pass = false; break; + case "currentDate": + md = moment(new Date()).format("D MMMM YYYY"); + break; default: if (this.options.syntax[this.style]) { md = this.options.syntax[this.style].replace('$1', text); @@ -84,16 +129,9 @@ italic: "_$1_", strike: "~~$1~~", code: "`$1`", - h1: "\n# $1\n", - h2: "\n## $1\n", - h3: "\n### $1\n", - h4: "\n#### $1\n", - h5: "\n##### $1\n", - h6: "\n###### $1\n", link: "[$1](http://)", image: "!image[$1](http://)", - blockquote: "> $1", - currentDate: new Date().toLocaleString() + blockquote: "> $1" } }; From 6bd3333d6ddd0f72996a24bd011f20f768812faf Mon Sep 17 00:00:00 2001 From: Matthew Harrison-Jones Date: Tue, 13 Aug 2013 11:53:49 +0100 Subject: [PATCH 3/3] Improved modals styling and code formatting Solves: * max-height 120px less than height of viewport * fade-in a dark overlay as well as blur * animation speeds/transitions should be smoother * modal sizing fucks up when viewport is resized Also improves Modal code compliance to Ghost Backbone coding patterns --- core/client/assets/sass/modules/global.scss | 9 ++- core/client/views/base.js | 71 +++++++++++---------- core/client/views/editor.js | 4 +- 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/core/client/assets/sass/modules/global.scss b/core/client/assets/sass/modules/global.scss index 02be82aeee..d3d1048346 100644 --- a/core/client/assets/sass/modules/global.scss +++ b/core/client/assets/sass/modules/global.scss @@ -902,6 +902,7 @@ nav { left: 0; right: 0; z-index: 999; + @include transition(background 300ms ease); &.dark { background: rgba(0,0,0,0.4); @@ -920,8 +921,14 @@ nav { } body.blur > *:not(#modal-container) { + @include transition(all 300ms ease); -webkit-filter: blur(2px); - filter: blur(2px); // Not used yet + -moz-filter: blur(2px); + -ms-filter: blur(2px); + -o-filter: blur(2px); + filter: blur(2px); + @include transform(translateZ(0)); + } %modal, .modal { diff --git a/core/client/views/base.js b/core/client/views/base.js index 4fc59e300d..7960cc7542 100644 --- a/core/client/views/base.js +++ b/core/client/views/base.js @@ -166,99 +166,100 @@ } }); - /** - * This is the view to generate the markup for the individual - * modal. Will be included into #modals. - * - * - * - * Types can be - * - (empty) - * - */ + // ## Modals Ghost.Views.Modal = Ghost.View.extend({ el: '#modal-container', templateName: 'modal', className: 'js-bb-modal', + // Render and manages modal dismissal initialize: function () { this.render(); var self = this; if (!this.model.options.confirm) { shortcut.add("ESC", function () { - self.removeItem(); + self.removeElement(); }); $(document).on('click', '.modal-background', function (e) { - self.removeItem(e); + self.removeElement(e); }); } else { // Initiate functions for buttons here so models don't get tied up. this.acceptModal = function () { this.model.options.confirm.accept.func(); - self.removeItem(); + self.removeElement(); }; this.rejectModal = function () { this.model.options.confirm.reject.func(); - self.removeItem(); + self.removeElement(); }; shortcut.remove("ESC"); $(document).off('click', '.modal-background'); } }, - template: function (data) { - return JST[this.templateName](data); + templateData: function () { + return this.model; }, events: { - 'click .close': 'removeItem', + 'click .close': 'removeElement', 'click .js-button-accept': 'acceptModal', 'click .js-button-reject': 'rejectModal' }, - render: function () { - this.$el.html(this.template(this.model)); + afterRender: function () { this.$(".modal-content").html(this.addSubview(new Ghost.Views.Modal.ContentView({model: this.model})).render().el); - this.$el.children(".js-modal").center(); - this.$el.addClass("active"); + this.$el.children(".js-modal").center().css("max-height", $(window).height() - 120); // same as resize(), but the debounce causes init lag + this.$el.addClass("active dark"); + if (document.body.style.webkitFilter !== undefined) { // Detect webkit filters $("body").addClass("blur"); - } else { - this.$el.addClass("dark"); } - return this; + + var self = this; + $(window).on('resize', self.resize); + }, + // #### resize + // Center and resize modal based on window height + resize: _.debounce(function () { + $(".js-modal").center().css("max-height", $(window).height() - 120); + }, 50), + // #### remove + // Removes Backbone attachments from modals remove: function () { this.undelegateEvents(); this.$el.empty(); this.stopListening(); return this; }, - removeItem: function (e) { + // #### removeElement + // Visually removes the modal from the user interface + removeElement: function (e) { if (e) { e.preventDefault(); e.stopPropagation(); } + + var self = this; + this.$el.removeClass('dark'); $('.js-modal').fadeOut(300, function () { $(this).remove(); - $("#modal-container").removeClass('active dark'); if (document.body.style.filter !== undefined) { $("body").removeClass("blur"); } + self.remove(); + self.$el.removeClass('active'); }); - this.remove(); + } }); - /** - * Modal Content - * @type {*} - */ + // ## Modal Content Ghost.Views.Modal.ContentView = Ghost.View.extend({ template: function (data) { return JST['modals/' + this.model.content.template](data); }, - - render: function () { - this.$el.html(this.template(this.model)); - return this; + templateData: function () { + return this.model; } }); diff --git a/core/client/views/editor.js b/core/client/views/editor.js index 45ecf7be78..11c1c82a00 100644 --- a/core/client/views/editor.js +++ b/core/client/views/editor.js @@ -23,14 +23,14 @@ {'key': 'Ctrl+Shift+L', 'style': 'link'}, {'key': 'Ctrl+Shift+I', 'style': 'image'}, {'key': 'Ctrl+Q', 'style': 'blockquote'}, - {'key': 'Ctrl+Shift+1', 'style': 'currentdate'}, + {'key': 'Ctrl+Shift+1', 'style': 'currentDate'}, {'key': 'Ctrl+U', 'style': 'uppercase'}, {'key': 'Ctrl+Shift+U', 'style': 'lowercase'}, {'key': 'Ctrl+Alt+Shift+U', 'style': 'titlecase'}, {'key': 'Ctrl+Alt+W', 'style': 'selectword'}, {'key': 'Ctrl+L', 'style': 'list'}, {'key': 'Ctrl+Alt+C', 'style': 'copyHTML'}, - {'key': 'CMD+Alt+C', 'style': 'copyHTML'} + {'key': 'Meta+Alt+C', 'style': 'copyHTML'} ]; // The publish bar associated with a post, which has the TagWidget and