diff --git a/core/client/assets/sass/layouts/post-settings-menu.scss b/core/client/assets/sass/layouts/post-settings-menu.scss index 73b34dc642..20fa8fa5a2 100644 --- a/core/client/assets/sass/layouts/post-settings-menu.scss +++ b/core/client/assets/sass/layouts/post-settings-menu.scss @@ -87,6 +87,9 @@ max-height: 250px; } + .word-count { + font-weight: bold; + } } diff --git a/core/client/components/gh-input.js b/core/client/components/gh-input.js new file mode 100644 index 0000000000..88dc5b6ddc --- /dev/null +++ b/core/client/components/gh-input.js @@ -0,0 +1,5 @@ +import TextInputMixin from 'ghost/mixins/text-input'; + +var Input = Ember.TextField.extend(TextInputMixin); + +export default Input; diff --git a/core/client/components/gh-textarea.js b/core/client/components/gh-textarea.js new file mode 100644 index 0000000000..fbbe45ea26 --- /dev/null +++ b/core/client/components/gh-textarea.js @@ -0,0 +1,5 @@ +import TextInputMixin from 'ghost/mixins/text-input'; + +var TextArea = Ember.TextArea.extend(TextInputMixin); + +export default TextArea; diff --git a/core/client/controllers/post-settings-menu.js b/core/client/controllers/post-settings-menu.js index 50403a4909..2136a5cde1 100644 --- a/core/client/controllers/post-settings-menu.js +++ b/core/client/controllers/post-settings-menu.js @@ -97,6 +97,38 @@ var PostSettingsMenuController = Ember.ObjectController.extend({ }); }, + metaTitleValue: boundOneWay('meta_title'), + + metaDescriptionValue: boundOneWay('meta_description'), + metaDescriptionPlaceholder: Ember.computed('scratch', function () { + var html = this.get('scratch'), + placeholder; + + // Strip HTML + placeholder = $('
', { html: html }).text(); + // Replace new lines and trim + placeholder = placeholder.replace(/\n+/g, ' ').trim(); + // Limit to 156 characters + placeholder = placeholder.substring(0,156); + + return placeholder; + }), + + seoTitle: Ember.computed('titleScratch', 'metaTitleValue', function () { + var metaTitle = this.get('metaTitleValue') || ''; + + return metaTitle.length > 0 ? metaTitle : this.get('titleScratch'); + }), + + seoDescription: Ember.computed('scratch', 'metaDescriptionValue', function () { + var metaDescription = this.get('metaDescriptionValue') || ''; + + return metaDescription.length > 0 ? metaDescription : this.get('metaDescriptionPlaceholder'); + }), + + seoSlug: Ember.computed('slug', 'slugPlaceholder', function () { + return this.get('slug') ? this.get('slug') : this.get('slugPlaceholder'); + }), // observe titleScratch, keeping the post's slug in sync // with it until saved for the first time. @@ -274,6 +306,40 @@ var PostSettingsMenuController = Ember.ObjectController.extend({ }); }, + setMetaTitle: function (metaTitle) { + var self = this; + + this.set('meta_title', metaTitle); + + // If this is a new post. Don't save the model. Defer the save + // to the user pressing the save button + if (this.get('isNew')) { + return; + } + + this.get('model').save(this.get('saveOptions')).catch(function (errors) { + self.showErrors(errors); + self.get('model').rollback(); + }); + }, + + setMetaDescription: function (metaDescription) { + var self = this; + + this.set('meta_description', metaDescription); + + // If this is a new post. Don't save the model. Defer the save + // to the user pressing the save button + if (this.get('isNew')) { + return; + } + + this.get('model').save(this.get('saveOptions')).catch(function (errors) { + self.showErrors(errors); + self.get('model').rollback(); + }); + }, + setCoverImage: function (image) { var self = this; diff --git a/core/client/helpers/gh-count-down-characters.js b/core/client/helpers/gh-count-down-characters.js new file mode 100644 index 0000000000..0712177702 --- /dev/null +++ b/core/client/helpers/gh-count-down-characters.js @@ -0,0 +1,17 @@ +var countDownCharacters = Ember.Handlebars.makeBoundHelper(function (content, maxCharacters) { + var el = document.createElement('span'), + length = content ? content.length : 0; + + el.className = 'word-count'; + if (length > maxCharacters) { + el.style.color = '#E25440'; + } else { + el.style.color = '#9E9D95'; + } + + el.innerHTML = length; + + return new Ember.Handlebars.SafeString(el.outerHTML); +}); + +export default countDownCharacters; \ No newline at end of file diff --git a/core/client/components/gh-blur-input.js b/core/client/mixins/text-input.js similarity index 79% rename from core/client/components/gh-blur-input.js rename to core/client/mixins/text-input.js index 84d771a6d2..f080ee2494 100644 --- a/core/client/components/gh-blur-input.js +++ b/core/client/mixins/text-input.js @@ -1,4 +1,4 @@ -var BlurInput = Ember.TextField.extend({ +var BlurField = Ember.Mixin.create({ selectOnClick: false, stopEnterKeyDownPropagation: false, click: function (event) { @@ -6,9 +6,6 @@ var BlurInput = Ember.TextField.extend({ event.currentTarget.select(); } }, - focusOut: function () { - this.sendAction('action', this.get('value')); - }, keyDown: function (event) { // stop event propagation when pressing "enter" // most useful in the case when undesired (global) keyboard shortcuts are getting triggered while interacting @@ -20,4 +17,4 @@ var BlurInput = Ember.TextField.extend({ } }); -export default BlurInput; +export default BlurField; \ No newline at end of file diff --git a/core/client/templates/post-settings-menu.hbs b/core/client/templates/post-settings-menu.hbs index 002f1a6c9b..e680552d0b 100644 --- a/core/client/templates/post-settings-menu.hbs +++ b/core/client/templates/post-settings-menu.hbs @@ -1,5 +1,5 @@
-{{!----for halfdan:{{#gh-tabs-manager selected="showSubview" id="entry-controls" classNameBindings="isNew:unsaved :right-outlet"}}----}} +{{#gh-tabs-manager selected="showSubview" id="entry-controls" classNameBindings="isNew:unsaved :right-outlet"}}
@@ -12,14 +12,14 @@
- {{gh-blur-input class="post-setting-slug" id="url" value=slugValue name="post-setting-slug" action="updateSlug" placeholder=slugPlaceholder selectOnClick="true" stopEnterKeyDownPropagation="true"}} + {{gh-input class="post-setting-slug" id="url" value=slugValue name="post-setting-slug" focus-out="updateSlug" placeholder=slugPlaceholder selectOnClick="true" stopEnterKeyDownPropagation="true"}}
- {{gh-blur-input class="post-setting-date" value=publishedAtValue name="post-setting-date" action="setPublishedAt" placeholder=publishedAtPlaceholder stopEnterKeyDownPropagation="true"}} + {{gh-input class="post-setting-date" value=publishedAtValue name="post-setting-date" focus-out="setPublishedAt" placeholder=publishedAtPlaceholder stopEnterKeyDownPropagation="true"}}
@@ -45,13 +45,13 @@
-
- {{!-----{{#gh-tab-pane}}-----}} + {{#gh-tab-pane}}

Meta Data

@@ -87,26 +87,26 @@
- -

Recommended: 70 characters. You’ve used 43

+ {{gh-input class="post-setting-meta-title" value=metaTitleValue name="post-setting-meta-title" focus-out="setMetaTitle" placeholder=titleScratch stopEnterKeyDownPropagation="true"}} +

Recommended: 70 characters. You’ve used {{gh-count-down-characters metaTitleValue 70}}

- -

Recommended: 156 characters. You’ve used 133

+ {{gh-textarea class="post-setting-meta-description" value=metaDescriptionValue name="post-setting-meta-description" focus-out="setMetaDescription" placeholder=metaDescriptionPlaceholder stopEnterKeyDownPropagation="true"}} +

Recommended: 156 characters. You’ve used {{gh-count-down-characters metaDescriptionValue 156}}

-
My Post is Super SEO Friendly
- -
In this fascinating posts I explore the value of SEO meta descriptions and their impact on blogging. Don’t miss my stunning insights!
+
{{seoTitle}}
+ +
{{seoDescription}}
- {{!---{{/gh-tab-pane}}----}} -
--> + {{/gh-tab-pane}} +
-{{!---{{/gh-tabs-manager}} ---}} +{{/gh-tabs-manager}} diff --git a/core/client/templates/settings/users/user.hbs b/core/client/templates/settings/users/user.hbs index 8852c258b1..1b5c257775 100644 --- a/core/client/templates/settings/users/user.hbs +++ b/core/client/templates/settings/users/user.hbs @@ -49,7 +49,7 @@
- {{gh-blur-input class="user-name" id="user-slug" value=slugValue name="user" action="updateSlug" placeholder="Slug" selectOnClick="true" autocorrect="off"}} + {{gh-input class="user-name" id="user-slug" value=slugValue name="user" focus-out="updateSlug" placeholder="Slug" selectOnClick="true" autocorrect="off"}}

{{gh-blog-url}}/author/{{slugValue}}