Meta data screen

closes #3939
- Add Seo Tab component to PSM
- Add new gh-blur-textarea component
- Refactor blur-input to use new text-input mixin
This commit is contained in:
Fabian Becker 2014-09-18 23:42:07 +00:00
parent 67c4452787
commit 30f56280e0
8 changed files with 115 additions and 22 deletions

View File

@ -87,6 +87,9 @@
max-height: 250px;
}
.word-count {
font-weight: bold;
}
}

View File

@ -0,0 +1,5 @@
import TextInputMixin from 'ghost/mixins/text-input';
var Input = Ember.TextField.extend(TextInputMixin);
export default Input;

View File

@ -0,0 +1,5 @@
import TextInputMixin from 'ghost/mixins/text-input';
var TextArea = Ember.TextArea.extend(TextInputMixin);
export default TextArea;

View File

@ -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 = $('<div />', { 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;

View File

@ -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;

View File

@ -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;

View File

@ -1,5 +1,5 @@
<div class="editor-cover" {{action "closeRightOutlet"}}></div>
{{!----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"}}
<div id="entry-controls" {{bind-attr class="isNew:unsaved :right-outlet"}}>
<div {{bind-attr class="isViewingSubview:outlet-pane-out-left:outlet-pane-in :post-settings-menu :outlet-pane"}}>
<div class="post-settings-header">
@ -12,14 +12,14 @@
<div class="form-group">
<label for="blog-title">Post URL</label>
<span class="input-icon icon-link">
{{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"}}
</span>
</div>
<div class="form-group">
<label for="blog-title">Publish Date</label>
<span class="input-icon icon-calendar">
{{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"}}
</span>
</div>
@ -45,13 +45,13 @@
</label>
</div>
<ul class="nav-list nav-list-block">
{{!--
{{#gh-tab tagName="li" classNames="nav-list-item"}}
<a href="#">
<b>Meta Data</b>
<span>Extra content for SEO and social media.</span>
</a>
{{/gh-tab}}
{{!--
{{#gh-tab tagName="li" classNames="nav-list-item"}}
<a href="#">
<b>Advanced Settings</b>
@ -75,9 +75,9 @@
<button type="button" class="btn btn-red icon-trash delete" {{action "openModal" "delete-post" this}}>Delete This Post</button>
</form>
</div><!-- .post-settings-content -->
</div><!-- .post-settings-menu --
</div><!-- .post-settings-menu -->
<div {{bind-attr class="isViewingSubview:outlet-pane-in:outlet-pane-out-right :post-settings-menu :outlet-pane"}}>
{{!-----{{#gh-tab-pane}}-----}}
{{#gh-tab-pane}}
<div class="post-settings-header subview">
<button {{action "closeSubview"}} class="back icon-chevron-left post-settings-header-action"><span class="hidden">Back</span></button>
<h4>Meta Data</h4>
@ -87,26 +87,26 @@
<div class="post-settings-content">
<div class="form-group">
<label for="blog-title">Meta Title</label>
<input type="text" value="My Post is Super SEO Friendly" />
<p>Recommended: <b>70</b> characters. Youve used <b class="green">43</b></p>
{{gh-input class="post-setting-meta-title" value=metaTitleValue name="post-setting-meta-title" focus-out="setMetaTitle" placeholder=titleScratch stopEnterKeyDownPropagation="true"}}
<p>Recommended: <b>70</b> characters. Youve used {{gh-count-down-characters metaTitleValue 70}}</p>
</div>
<div class="form-group">
<label for="blog-title">Meta Description</label>
<textarea>In this fascinating posts I explore the value of SEO meta descriptions and their impact on blogging. Dont miss my stunning insights!</textarea>
<p>Recommended: <b>156</b> characters. Youve used <b class="green">133</b></p>
{{gh-textarea class="post-setting-meta-description" value=metaDescriptionValue name="post-setting-meta-description" focus-out="setMetaDescription" placeholder=metaDescriptionPlaceholder stopEnterKeyDownPropagation="true"}}
<p>Recommended: <b>156</b> characters. Youve used {{gh-count-down-characters metaDescriptionValue 156}}</p>
</div>
<div class="form-group">
<label>Search Engine Result Preview</label>
<div class="seo-preview">
<div class="seo-preview-title">My Post is Super SEO Friendly</div>
<div class="seo-preview-link">myblog.com/this-is-my-post/</div>
<div class="seo-preview-description">In this fascinating posts I explore the value of SEO meta descriptions and their impact on blogging. Dont miss my stunning insights!</div>
<div class="seo-preview-title">{{seoTitle}}</div>
<div class="seo-preview-link">{{gh-blog-url}}/{{seoSlug}}{{#if seoSlug}}/{{/if}}</div>
<div class="seo-preview-description">{{seoDescription}}</div>
</div>
</div>
</div>
{{!---{{/gh-tab-pane}}----}}
</div>-->
{{/gh-tab-pane}}
</div>
</div>
{{!---{{/gh-tabs-manager}} ---}}
{{/gh-tabs-manager}}

View File

@ -49,7 +49,7 @@
<div class="form-group">
<label for="user-slug">Slug</label>
{{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"}}
<p>{{gh-blog-url}}/author/{{slugValue}}</p>
</div>