mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-05 18:34:39 +03:00
commit
69ea28e951
27
core/client/components/gh-tab-pane.js
Normal file
27
core/client/components/gh-tab-pane.js
Normal file
@ -0,0 +1,27 @@
|
||||
//See gh-tabs-manager.js for use
|
||||
var TabPane = Ember.Component.extend({
|
||||
classNameBindings: ['active'],
|
||||
|
||||
tabsManager: Ember.computed(function () {
|
||||
return this.nearestWithProperty('isTabsManager');
|
||||
}),
|
||||
|
||||
tab: Ember.computed('tabsManager.tabs.@each', function () {
|
||||
var index = this.get('tabsManager.tabPanes').indexOf(this),
|
||||
tabs = this.get('tabsManager.tabs');
|
||||
|
||||
return tabs && tabs.objectAt(index);
|
||||
}),
|
||||
|
||||
active: Ember.computed.alias('tab.active'),
|
||||
|
||||
// Register with the tabs manager
|
||||
registerWithTabs: function () {
|
||||
this.get('tabsManager').registerTabPane(this);
|
||||
}.on('didInsertElement'),
|
||||
unregisterWithTabs: function () {
|
||||
this.get('tabsManager').unregisterTabPane(this);
|
||||
}.on('willDestroyElement')
|
||||
});
|
||||
|
||||
export default TabPane;
|
30
core/client/components/gh-tab.js
Normal file
30
core/client/components/gh-tab.js
Normal file
@ -0,0 +1,30 @@
|
||||
//See gh-tabs-manager.js for use
|
||||
var Tab = Ember.Component.extend({
|
||||
tabsManager: Ember.computed(function () {
|
||||
return this.nearestWithProperty('isTabsManager');
|
||||
}),
|
||||
|
||||
active: Ember.computed('tabsManager.activeTab', function () {
|
||||
return this.get('tabsManager.activeTab') === this;
|
||||
}),
|
||||
|
||||
index: Ember.computed('tabsManager.tabs.@each', function () {
|
||||
return this.get('tabsManager.tabs').indexOf(this);
|
||||
}),
|
||||
|
||||
// Select on click
|
||||
click: function () {
|
||||
this.get('tabsManager').select(this);
|
||||
},
|
||||
|
||||
// Registration methods
|
||||
registerWithTabs: function () {
|
||||
this.get('tabsManager').registerTab(this);
|
||||
}.on('didInsertElement'),
|
||||
|
||||
unregisterWithTabs: function () {
|
||||
this.get('tabsManager').unregisterTab(this);
|
||||
}.on('willDestroyElement')
|
||||
});
|
||||
|
||||
export default Tab;
|
80
core/client/components/gh-tabs-manager.js
Normal file
80
core/client/components/gh-tabs-manager.js
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
Heavily inspired by ic-tabs (https://github.com/instructure/ic-tabs)
|
||||
|
||||
Three components work together for smooth tabbing.
|
||||
1. tabs-manager (gh-tabs)
|
||||
2. tab (gh-tab)
|
||||
3. tab-pane (gh-tab-pane)
|
||||
|
||||
## Usage:
|
||||
The tabs-manager must wrap all tab and tab-pane components,
|
||||
but they can be nested at any level.
|
||||
|
||||
A tab and its pane are tied together via their order.
|
||||
So, the second tab within a tab manager will activate
|
||||
the second pane within that manager.
|
||||
|
||||
```hbs
|
||||
{{#gh-tabs-manager}}
|
||||
{{#gh-tab}}
|
||||
First tab
|
||||
{{/gh-tab}}
|
||||
{{#gh-tab}}
|
||||
Second tab
|
||||
{{/gh-tab}}
|
||||
|
||||
....
|
||||
{{#gh-tab-pane}}
|
||||
First pane
|
||||
{{/gh-tab-pane}}
|
||||
{{#gh-tab-pane}}
|
||||
Second pane
|
||||
{{/gh-tab-pane}}
|
||||
{{/gh-tabs-manager}}
|
||||
```
|
||||
|
||||
## Options:
|
||||
|
||||
the tabs-manager will send a "selected" action whenever one of its
|
||||
tabs is clicked.
|
||||
```hbs
|
||||
{{#gh-tabs-manager selected="myAction"}}
|
||||
....
|
||||
{{/gh-tabs-manager}}
|
||||
```
|
||||
|
||||
## Styling:
|
||||
Both tab and tab-pane elements have an "active"
|
||||
class applied when they are active.
|
||||
|
||||
*/
|
||||
var TabsManager = Ember.Component.extend({
|
||||
activeTab: null,
|
||||
tabs: [],
|
||||
tabPanes: [],
|
||||
|
||||
// Called when a gh-tab is clicked.
|
||||
select: function (tab) {
|
||||
this.set('activeTab', tab);
|
||||
this.sendAction('selected');
|
||||
},
|
||||
|
||||
//Used by children to find this tabsManager
|
||||
isTabsManager: true,
|
||||
// Register tabs and their panes to allow for
|
||||
// interaction between components.
|
||||
registerTab: function (tab) {
|
||||
this.get('tabs').addObject(tab);
|
||||
},
|
||||
unregisterTab: function (tab) {
|
||||
this.get('tabs').removeObject(tab);
|
||||
},
|
||||
registerTabPane: function (tabPane) {
|
||||
this.get('tabPanes').addObject(tabPane);
|
||||
},
|
||||
unregisterTabPane: function (tabPane) {
|
||||
this.get('tabPanes').removeObject(tabPane);
|
||||
}
|
||||
});
|
||||
|
||||
export default TabsManager;
|
@ -3,12 +3,9 @@ var ApplicationController = Ember.Controller.extend({
|
||||
|
||||
topNotificationCount: 0,
|
||||
showGlobalMobileNav: false,
|
||||
showRightOutlet: false,
|
||||
|
||||
actions: {
|
||||
toggleMenu: function () {
|
||||
this.toggleProperty('showMenu');
|
||||
},
|
||||
|
||||
topNotificationChange: function (count) {
|
||||
this.set('topNotificationCount', count);
|
||||
}
|
||||
|
@ -4,18 +4,18 @@ import SlugGenerator from 'ghost/models/slug-generator';
|
||||
import boundOneWay from 'ghost/utils/bound-one-way';
|
||||
|
||||
var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
init: function () {
|
||||
this._super();
|
||||
},
|
||||
|
||||
initializeObserver: function () {
|
||||
// when creating a new post we want to observe the title
|
||||
// to generate the post's slug
|
||||
if (this.get('isNew')) {
|
||||
this.addObserver('titleScratch', this, 'titleObserver');
|
||||
//State for if the user is viewing a tab's pane.
|
||||
needs: 'application',
|
||||
isViewingSubview: Ember.computed('controllers.application.showRightOutlet', function (key, value) {
|
||||
// Not viewing a subview if we can't even see the PSM
|
||||
if (!this.get('controllers.application.showRightOutlet')) {
|
||||
return false;
|
||||
}
|
||||
}.observes('model'),
|
||||
|
||||
if (arguments.length > 1) {
|
||||
return value;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
selectedAuthor: null,
|
||||
initializeSelectedAuthor: function () {
|
||||
var self = this;
|
||||
@ -96,6 +96,15 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
self.set('slugPlaceholder', slug);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// observe titleScratch, keeping the post's slug in sync
|
||||
// with it until saved for the first time.
|
||||
addTitleObserver: function () {
|
||||
if (this.get('isNew')) {
|
||||
this.addObserver('titleScratch', this, 'titleObserver');
|
||||
}
|
||||
}.observes('model'),
|
||||
titleObserver: function () {
|
||||
if (this.get('isNew') && !this.get('title')) {
|
||||
Ember.run.debounce(this, 'generateSlugPlaceholder', 700);
|
||||
@ -293,6 +302,14 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
self.showErrors(errors);
|
||||
self.get('model').rollback();
|
||||
});
|
||||
},
|
||||
|
||||
showSubview: function () {
|
||||
this.set('isViewingSubview', true);
|
||||
},
|
||||
|
||||
closeSubview: function () {
|
||||
this.set('isViewingSubview', false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -20,12 +20,6 @@ var EditorRouteBase = Ember.Mixin.create(styleBody, ShortcutsRoute, loadingIndic
|
||||
//The actual functionality is implemented in utils/codemirror-shortcuts
|
||||
codeMirrorShortcut: function (options) {
|
||||
this.get('controller.codemirror').shortcut(options.type);
|
||||
},
|
||||
togglePostSettings: function () {
|
||||
Ember.$('body').toggleClass('right-outlet-expanded');
|
||||
},
|
||||
closePostSettings: function () {
|
||||
Ember.$('body').removeClass('right-outlet-expanded');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -29,6 +29,13 @@ var ApplicationRoute = Ember.Route.extend(SimpleAuth.ApplicationRouteMixin, Shor
|
||||
this.toggleProperty('controller.showGlobalMobileNav');
|
||||
},
|
||||
|
||||
toggleRightOutlet: function () {
|
||||
this.toggleProperty('controller.showRightOutlet');
|
||||
},
|
||||
closeRightOutlet: function () {
|
||||
this.set('controller.showRightOutlet', false);
|
||||
},
|
||||
|
||||
closePopups: function () {
|
||||
this.get('popover').closePopovers();
|
||||
this.get('notifications').closeAll();
|
||||
|
@ -77,6 +77,8 @@ var EditorEditRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, bas
|
||||
isDeleted = model.get('isDeleted'),
|
||||
modelIsDirty = model.get('isDirty');
|
||||
|
||||
this.send('closeRightOutlet');
|
||||
|
||||
// when `isDeleted && isSaving`, model is in-flight, being saved
|
||||
// to the server. when `isDeleted && !isSaving && !modelIsDirty`,
|
||||
// the record has already been deleted and the deletion persisted.
|
||||
|
@ -34,6 +34,8 @@ var EditorNewRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, base
|
||||
isDeleted = model.get('isDeleted'),
|
||||
modelIsDirty = model.get('isDirty');
|
||||
|
||||
this.send('closeRightOutlet');
|
||||
|
||||
// when `isDeleted && isSaving`, model is in-flight, being saved
|
||||
// to the server. when `isDeleted && !isSaving && !modelIsDirty`,
|
||||
// the record has already been deleted and the deletion persisted.
|
||||
|
@ -2,7 +2,7 @@
|
||||
{{render 'post-tags-input'}}
|
||||
|
||||
<div class="right">
|
||||
<button type="button" class='post-settings' {{action "togglePostSettings"}}></button>
|
||||
<button type="button" class='post-settings' {{action "toggleRightOutlet"}}></button>
|
||||
|
||||
{{view "editor-save-button" id="entry-actions"}}
|
||||
</div>
|
||||
|
@ -1,4 +1,3 @@
|
||||
<div id="container">
|
||||
<a class="sr-only sr-only-focusable" href="#gh-main">Skip to main content</a>
|
||||
|
||||
{{#unless hideNav}}
|
||||
@ -14,5 +13,3 @@
|
||||
{{outlet modal}}
|
||||
|
||||
{{outlet settings-menu}}
|
||||
|
||||
</div>
|
@ -1,9 +1,10 @@
|
||||
<div class="editor-cover" {{action "closePostSettings"}}></div>
|
||||
<div id="entry-controls" {{bind-attr class=":right-outlet isNew:unsaved"}}>
|
||||
<div class="post-settings-menu outlet-pane outlet-pane-in">
|
||||
<div class="editor-cover" {{action "closeRightOutlet"}}></div>
|
||||
{{!----for halfdan:{{#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">
|
||||
<h4>Post Settings</h4>
|
||||
<button class="close icon-x post-settings-header-action" {{action "closePostSettings"}}><span class="hidden">Close</span></button>
|
||||
<button class="close icon-x post-settings-header-action" {{action "closeRightOutlet"}}><span class="hidden">Close</span></button>
|
||||
</div>
|
||||
<div class="post-settings-content">
|
||||
{{gh-uploader uploaded="setCoverImage" canceled="clearCoverImage" image=image tagName="section"}}
|
||||
@ -43,46 +44,46 @@
|
||||
<p>Static Page</p>
|
||||
</label>
|
||||
</div>
|
||||
<!--
|
||||
<ul class="nav-list nav-list-block">
|
||||
<li class="nav-list-item">
|
||||
<a href="#">
|
||||
<b>Revision History</b>
|
||||
<span>12 versions of this post by 3 people.</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-list-item">
|
||||
<a href="#">
|
||||
<b>Advanced Settings</b>
|
||||
<span>Convert to a page, mark as featured.</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-list-item">
|
||||
{{!--
|
||||
{{#gh-tab tagName="li" classNames="nav-list-item"}}
|
||||
<a href="#">
|
||||
<b>Meta Data</b>
|
||||
<span>Extra content for SEO and social media.</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-list-item">
|
||||
{{/gh-tab}}
|
||||
{{#gh-tab tagName="li" classNames="nav-list-item"}}
|
||||
<a href="#">
|
||||
<b>Advanced Settings</b>
|
||||
<span>Convert to a page, mark as featured.</span>
|
||||
</a>
|
||||
{{/gh-tab}}
|
||||
{{#gh-tab tagName="li" classNames="nav-list-item"}}
|
||||
<a href="#">
|
||||
<b>Revision History</b>
|
||||
<span>12 versions of this post by 3 people.</span>
|
||||
</a>
|
||||
{{/gh-tab}}
|
||||
{{#gh-tab tagName="li" classNames="nav-list-item"}}
|
||||
<a href="#">
|
||||
<b>Custom App</b>
|
||||
<span>Registered an advanced setting panel.</span>
|
||||
</a>
|
||||
</li>
|
||||
{{/gh-tab}}
|
||||
--}}
|
||||
</ul>
|
||||
-->
|
||||
<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 class="post-settings-menu outlet-pane outlet-pane-out-right">
|
||||
|
||||
</div><!-- .post-settings-menu --
|
||||
<div {{bind-attr class="isViewingSubview:outlet-pane-in:outlet-pane-out-right :post-settings-menu :outlet-pane"}}>
|
||||
{{!-----{{#gh-tab-pane}}-----}}
|
||||
<div class="post-settings-header subview">
|
||||
<button class="back icon-chevron-left post-settings-header-action"><span class="hidden">Back</span></button>
|
||||
<button {{action "closeSubview"}} class="back icon-chevron-left post-settings-header-action"><span class="hidden">Back</span></button>
|
||||
<h4>Meta Data</h4>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="post-settings-content">
|
||||
<div class="form-group">
|
||||
<label for="blog-title">Meta Title</label>
|
||||
@ -105,6 +106,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
{{!---{{/gh-tab-pane}}----}}
|
||||
</div>-->
|
||||
</div>
|
||||
{{!---{{/gh-tabs-manager}} ---}}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import mobileQuery from 'ghost/utils/mobile';
|
||||
|
||||
var ApplicationView = Ember.View.extend({
|
||||
elementId: 'container',
|
||||
|
||||
blogRoot: Ember.computed.alias('controller.ghostPaths.blogRoot'),
|
||||
|
||||
setupGlobalMobileNav: function () {
|
||||
@ -56,6 +58,10 @@ var ApplicationView = Ember.View.extend({
|
||||
mobileQuery.removeListener(this.closeGlobalMobileNavOnDesktop);
|
||||
}.on('willDestroyElement'),
|
||||
|
||||
|
||||
toggleRightOutletBodyClass: function () {
|
||||
$('body').toggleClass('right-outlet-expanded', this.get('controller.showRightOutlet'));
|
||||
}.observes('controller.showRightOutlet')
|
||||
});
|
||||
|
||||
export default ApplicationView;
|
||||
|
@ -7,11 +7,7 @@ var PostSettingsMenuView = Ember.View.extend({
|
||||
publishedAtBinding: Ember.Binding.oneWay('controller.publishedAt'),
|
||||
datePlaceholder: Ember.computed('controller.publishedAt', function () {
|
||||
return formatDate(moment());
|
||||
}),
|
||||
|
||||
animateOut: function () {
|
||||
$('body').removeClass('right-outlet-expanded');
|
||||
}.on('willDestroyElement')
|
||||
})
|
||||
});
|
||||
|
||||
export default PostSettingsMenuView;
|
||||
|
Loading…
Reference in New Issue
Block a user