mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Added popover component
Closes #2418, #2714 Ref #2446, #2565 - Added and injected `popover` service to globally control popovers - Added `gh-popover-button` component - Added `popover-mixin` for popover and popover-buttons to mixin - Added body-event-listener mixin for popover service to watch for body clicks with - Post settings and post save button both now use `gh-popover` - Added hacks to `ember-hacks.css` to make popovers work until ghost-ui consolidates functionality
This commit is contained in:
parent
a8164c7d3f
commit
37fd17c084
11 changed files with 183 additions and 49 deletions
|
@ -15,17 +15,22 @@
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
By default nav menu should be displayed as it's visibility is controllerd
|
|
||||||
by GhostPopover
|
|
||||||
*/
|
|
||||||
.navbar .subnav ul {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Styles for GhostPopoverComponent
|
Styles for GhostPopoverComponent
|
||||||
*/
|
|
||||||
|
hack the user menu and for the post-save button popup,
|
||||||
|
until ghost-ui gets a rehaul
|
||||||
|
*/
|
||||||
|
.navbar .subnav ul.ghost-popover,
|
||||||
|
#publish-bar .splitbutton-save .editor-options.ghost-popover,
|
||||||
|
#publish-bar .splitbutton-delete .editor-options.ghost-popover{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#publish-bar .splitbutton-save .editor-options.ghost-popover.open,
|
||||||
|
#publish-bar .splitbutton-delete .editor-options.ghost-popover.open,
|
||||||
|
.navbar .subnav ul.ghost-popover.open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.ghost-popover {
|
.ghost-popover {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -34,11 +39,14 @@
|
||||||
.ghost-popover.open {
|
.ghost-popover.open {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Fade in animation */
|
||||||
.fade-in {
|
.fade-in {
|
||||||
animation: fadein 0.5s;
|
-o-animation: fadein 0.5s; /* Opera */
|
||||||
-moz-animation: fadein 0.5s; /* Firefox */
|
-moz-animation: fadein 0.5s; /* Firefox */
|
||||||
-webkit-animation: fadein 0.5s; /* Safari and Chrome */
|
-webkit-animation: fadein 0.5s; /* Safari and Chrome */
|
||||||
-o-animation: fadein 0.5s; /* Opera */
|
animation: fadein 0.5s;
|
||||||
}
|
}
|
||||||
@keyframes fadein {
|
@keyframes fadein {
|
||||||
from {
|
from {
|
||||||
|
@ -48,6 +56,14 @@
|
||||||
opacity:1;
|
opacity:1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@-o-keyframes fadein { /* Opera */
|
||||||
|
from {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@-moz-keyframes fadein { /* Firefox */
|
@-moz-keyframes fadein { /* Firefox */
|
||||||
from {
|
from {
|
||||||
opacity:0;
|
opacity:0;
|
||||||
|
@ -64,11 +80,3 @@
|
||||||
opacity:1;
|
opacity:1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@-o-keyframes fadein { /* Opera */
|
|
||||||
from {
|
|
||||||
opacity:0;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
14
core/client/components/gh-popover-button.js
Normal file
14
core/client/components/gh-popover-button.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import PopoverMixin from 'ghost/mixins/popover-mixin';
|
||||||
|
|
||||||
|
var PopoverButton = Ember.Component.extend(PopoverMixin, {
|
||||||
|
tagName: "button",
|
||||||
|
/*matches with the popover this button toggles*/
|
||||||
|
popoverName: null,
|
||||||
|
/*Notify popover service this popover should be toggled*/
|
||||||
|
click: function (event) {
|
||||||
|
this._super(event);
|
||||||
|
this.get('popover').togglePopover(this.get('popoverName'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default PopoverButton;
|
|
@ -1,8 +1,46 @@
|
||||||
|
import PopoverMixin from 'ghost/mixins/popover-mixin';
|
||||||
|
|
||||||
var GhostPopover = Ember.Component.extend({
|
var GhostPopover = Ember.Component.extend(PopoverMixin, {
|
||||||
classNames: 'ghost-popover',
|
classNames: 'ghost-popover fade-in',
|
||||||
classNameBindings: ['open'],
|
classNameBindings: ['open'],
|
||||||
open: false
|
name: null,
|
||||||
|
closeOnClick: false,
|
||||||
|
didInsertElement: function () {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
var popoverService = this.get('popover');
|
||||||
|
|
||||||
|
popoverService.on('close', this, this.close);
|
||||||
|
popoverService.on('toggle', this, this.toggle);
|
||||||
|
},
|
||||||
|
willDestroyElement: function () {
|
||||||
|
this._super();
|
||||||
|
var popoverService = this.get('popover');
|
||||||
|
|
||||||
|
popoverService.off('close', this, this.close);
|
||||||
|
popoverService.off('toggle', this, this.toggle);
|
||||||
|
},
|
||||||
|
click: function (event) {
|
||||||
|
this._super(event);
|
||||||
|
if (this.get('closeOnClick')) {
|
||||||
|
return this.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close: function () {
|
||||||
|
return this.set('open', false);
|
||||||
|
},
|
||||||
|
toggle: function (options) {
|
||||||
|
/*
|
||||||
|
Close all popovers whose button was not clicked,
|
||||||
|
and toggle the actual target.
|
||||||
|
*/
|
||||||
|
var targetPopoverName = options.target;
|
||||||
|
if (this.get('name') === targetPopoverName) {
|
||||||
|
this.toggleProperty('open');
|
||||||
|
} else {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default GhostPopover;
|
export default GhostPopover;
|
25
core/client/initializers/popover.js
Normal file
25
core/client/initializers/popover.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import BodyEventListener from 'ghost/mixins/body-event-listener';
|
||||||
|
|
||||||
|
var PopoverService = Ember.Object.extend(Ember.Evented, BodyEventListener, {
|
||||||
|
bodyClick: function (event) {
|
||||||
|
/*jshint unused:false */
|
||||||
|
this.closePopovers();
|
||||||
|
},
|
||||||
|
closePopovers: function () {
|
||||||
|
this.trigger('close');
|
||||||
|
},
|
||||||
|
togglePopover: function (popoverName) {
|
||||||
|
this.trigger('toggle', {target: popoverName});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'popover',
|
||||||
|
|
||||||
|
initialize: function (container, application) {
|
||||||
|
application.register('popover:service', PopoverService);
|
||||||
|
|
||||||
|
application.inject('component:gh-popover', 'popover', 'popover:service');
|
||||||
|
application.inject('component:gh-popover-button', 'popover', 'popover:service');
|
||||||
|
}
|
||||||
|
};
|
38
core/client/mixins/body-event-listener.js
Normal file
38
core/client/mixins/body-event-listener.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
Code modified from Addepar/ember-widgets
|
||||||
|
https://github.com/Addepar/ember-widgets/blob/master/src/mixins.coffee#L39
|
||||||
|
*/
|
||||||
|
var BodyEventListener = Ember.Mixin.create({
|
||||||
|
bodyElementSelector: 'html',
|
||||||
|
bodyClick: Ember.K,
|
||||||
|
init: function () {
|
||||||
|
this._super();
|
||||||
|
return Ember.run.next(this, this._setupDocumentHandlers);
|
||||||
|
},
|
||||||
|
willDestroy: function () {
|
||||||
|
this._super();
|
||||||
|
return this._removeDocumentHandlers();
|
||||||
|
},
|
||||||
|
_setupDocumentHandlers: function () {
|
||||||
|
if (this._clickHandler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var self = this;
|
||||||
|
this._clickHandler = function () {
|
||||||
|
return self.bodyClick();
|
||||||
|
};
|
||||||
|
return $(this.get('bodyElementSelector')).on('click', this._clickHandler);
|
||||||
|
},
|
||||||
|
_removeDocumentHandlers: function () {
|
||||||
|
$(this.get('bodyElementSelector')).off('click', this._clickHandler);
|
||||||
|
this._clickHandler = null;
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
http://stackoverflow.com/questions/152975/how-to-detect-a-click-outside-an-element
|
||||||
|
*/
|
||||||
|
click: function (event) {
|
||||||
|
return event.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default BodyEventListener;
|
11
core/client/mixins/popover-mixin.js
Normal file
11
core/client/mixins/popover-mixin.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/*
|
||||||
|
Popovers and their buttons are evented and do not propagate clicks.
|
||||||
|
*/
|
||||||
|
var PopoverMixin = Ember.Mixin.create(Ember.Evented, {
|
||||||
|
click: function (event) {
|
||||||
|
this._super(event);
|
||||||
|
return event.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default PopoverMixin;
|
|
@ -14,8 +14,11 @@
|
||||||
{{#link-to "editor" this class="post-edit" title="Edit Post"}}
|
{{#link-to "editor" this class="post-edit" title="Edit Post"}}
|
||||||
<span class="hidden">Edit Post</span>
|
<span class="hidden">Edit Post</span>
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
<a class="post-settings" title="Post Settings" {{action 'editSettings'}}><span class="hidden">Post Settings</span></a>
|
{{#gh-popover-button popoverName="post-settings-menu" tagName="a" classNames="post-settings" title="Post Settings"}}
|
||||||
<!-- @TODO use Ghost Popover (#2565) --->
|
<span class="hidden">Post Settings</span>
|
||||||
{{view "post-settings-menu-view"}}
|
{{/gh-popover-button}}
|
||||||
|
{{#gh-popover name="post-settings-menu" classNames="post-settings-menu menu-drop-right"}}
|
||||||
|
{{view "post-settings-menu-view"}}
|
||||||
|
{{/gh-popover}}
|
||||||
</section>
|
</section>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -9,23 +9,21 @@
|
||||||
{{gh-activating-list-item route="settings" title="Settings" classNames="settings"}}
|
{{gh-activating-list-item route="settings" title="Settings" classNames="settings"}}
|
||||||
|
|
||||||
<li id="usermenu" class="usermenu subnav">
|
<li id="usermenu" class="usermenu subnav">
|
||||||
<a href="javascript:void(0);" {{action 'toggleMenu'}} class="dropdown">
|
{{#gh-popover-button popoverName="user-menu" tagName="a" href="#" classNames="dropdown"}}
|
||||||
{{#if user.image}}
|
{{#if user.image}}
|
||||||
<img class="avatar" {{bind-attr src="user.image"}} alt="Avatar" />
|
<img class="avatar" {{bind-attr src="user.image"}} alt="Avatar" />
|
||||||
{{else}}
|
{{else}}
|
||||||
<img class="avatar" src="/shared/img/user-image.png" alt="Avatar" />
|
<img class="avatar" src="/shared/img/user-image.png" alt="Avatar" />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<span class="name">{{user.name}}</span>
|
<span class="name">{{user.name}}</span>
|
||||||
</a>
|
{{/gh-popover-button}}
|
||||||
{{!-- @TODO: add functionality to allow for dropdown to work --}}
|
{{!-- @TODO: add functionality to allow for dropdown to work --}}
|
||||||
{{#gh-popover open=showMenu}}
|
{{#gh-popover tagName="ul" classNames="overlay" name="user-menu" closeOnClick="true"}}
|
||||||
<ul class="overlay">
|
|
||||||
<li class="usermenu-profile">{{#link-to 'settings.user'}}Your Profile{{/link-to}}</li>
|
<li class="usermenu-profile">{{#link-to 'settings.user'}}Your Profile{{/link-to}}</li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<li class="usermenu-help"><a href="http://ghost.org/forum/">Help / Support</a></li>
|
<li class="usermenu-help"><a href="http://ghost.org/forum/">Help / Support</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<li class="usermenu-signout"><a href="#">Sign Out</a></li>
|
<li class="usermenu-signout"><a href="#">Sign Out</a></li>
|
||||||
</ul>
|
|
||||||
{{/gh-popover}}
|
{{/gh-popover}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -14,9 +14,12 @@
|
||||||
<div class="right">
|
<div class="right">
|
||||||
|
|
||||||
<section id="entry-controls">
|
<section id="entry-controls">
|
||||||
<a class="post-settings" title="Post Settings" {{action 'editSettings'}}><span class="hidden">Post Settings</span></a>
|
{{#gh-popover-button popoverName="post-settings-menu" tagName="a" href="#" classNames="post-settings" title="Post Settings"}}
|
||||||
<!-- @TODO Use Ghost Popover (#2565) and style arrow down -->
|
<span class="hidden">Post Settings</span>
|
||||||
{{view "post-settings-menu-view"}}
|
{{/gh-popover-button}}
|
||||||
|
{{#gh-popover name="post-settings-menu" classNames="post-settings-menu menu-right"}}
|
||||||
|
{{view "post-settings-menu-view"}}
|
||||||
|
{{/gh-popover}}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{{view "editor-save-button" id="entry-actions"}}
|
{{view "editor-save-button" id="entry-actions"}}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
<button type="button" {{action "save"}} {{bind-attr class="view.isDangerous:button-delete:button-save :js-publish-button" }}>{{view.save-text}}</button>
|
<button type="button" {{action "save"}} {{bind-attr class="view.isDangerous:button-delete:button-save :js-publish-button" }}>
|
||||||
<button {{action 'viewSaveTypes'}} {{bind-attr class="controller.isViewingSaveTypes:active :options :up" }} title="Post Settings"><span class="hidden">Post Settings</span>
|
{{view.save-text}}
|
||||||
</button>
|
</button>
|
||||||
{{!-- @TODO: implement popover --}}
|
{{#gh-popover-button popoverName="post-save-menu" classNameBindings="open:active :options :up" title="Post Settings"}}
|
||||||
<ul {{bind-attr class="controller.isViewingSaveTypes::hidden :editor-options :overlay" }}>
|
<span class="hidden">Post Settings</span>
|
||||||
<li {{bind-attr class="controller.willPublish:active"}}>
|
{{/gh-popover-button}}
|
||||||
<a {{action "setSaveType" "publish"}} href="#">{{view.publish-text}}</a>
|
{{#gh-popover name="post-save-menu" closeOnClick="true" tagName="ul" classNames="editor-options overlay" publishTextBinding=view.publish-text draftTextBinding=view.draft-text}}
|
||||||
|
<li {{bind-attr class="controller.willPublish:active" }}>
|
||||||
|
<a {{action "setSaveType" "publish"}} href="#">{{view.publishText}}</a>
|
||||||
</li>
|
</li>
|
||||||
<li {{bind-attr class="controller.willPublish::active"}}>
|
<li {{bind-attr class="controller.willPublish::active" }}>
|
||||||
<a {{action "setSaveType" "draft"}} href="#">{{view.draft-text}}</a>
|
<a {{action "setSaveType" "draft"}} href="#">{{view.draftText}}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
{{/gh-popover}}
|
|
@ -3,13 +3,7 @@ import {formatDate} from 'ghost/utils/date-formatting';
|
||||||
|
|
||||||
var PostSettingsMenuView = Ember.View.extend({
|
var PostSettingsMenuView = Ember.View.extend({
|
||||||
templateName: 'post-settings-menu',
|
templateName: 'post-settings-menu',
|
||||||
classNames: ['post-settings-menu', 'menu-drop-right', 'overlay'],
|
|
||||||
classNameBindings: ['controller.isEditingSettings::hidden'],
|
|
||||||
publishedAtBinding: Ember.Binding.oneWay('controller.publishedAt'),
|
publishedAtBinding: Ember.Binding.oneWay('controller.publishedAt'),
|
||||||
click: function (event) {
|
|
||||||
//Stop click propagation to prevent window closing
|
|
||||||
event.stopPropagation();
|
|
||||||
},
|
|
||||||
datePlaceholder: function () {
|
datePlaceholder: function () {
|
||||||
return formatDate(moment());
|
return formatDate(moment());
|
||||||
}.property('controller.publishedAt')
|
}.property('controller.publishedAt')
|
||||||
|
|
Loading…
Add table
Reference in a new issue