0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-03 23:00: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:
Matt Enlow 2014-05-30 18:07:15 -06:00
parent a8164c7d3f
commit 37fd17c084
11 changed files with 183 additions and 49 deletions

View file

@ -15,17 +15,22 @@
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
*/
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 {
display: none;
@ -34,11 +39,14 @@
.ghost-popover.open {
display: block;
}
/* Fade in animation */
.fade-in {
animation: fadein 0.5s;
-o-animation: fadein 0.5s; /* Opera */
-moz-animation: fadein 0.5s; /* Firefox */
-webkit-animation: fadein 0.5s; /* Safari and Chrome */
-o-animation: fadein 0.5s; /* Opera */
animation: fadein 0.5s;
}
@keyframes fadein {
from {
@ -48,6 +56,14 @@
opacity:1;
}
}
@-o-keyframes fadein { /* Opera */
from {
opacity:0;
}
to {
opacity: 1;
}
}
@-moz-keyframes fadein { /* Firefox */
from {
opacity:0;
@ -64,11 +80,3 @@
opacity:1;
}
}
@-o-keyframes fadein { /* Opera */
from {
opacity:0;
}
to {
opacity: 1;
}
}

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

View file

@ -1,8 +1,46 @@
import PopoverMixin from 'ghost/mixins/popover-mixin';
var GhostPopover = Ember.Component.extend({
classNames: 'ghost-popover',
var GhostPopover = Ember.Component.extend(PopoverMixin, {
classNames: 'ghost-popover fade-in',
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;

View 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');
}
};

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

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

View file

@ -14,8 +14,11 @@
{{#link-to "editor" this class="post-edit" title="Edit Post"}}
<span class="hidden">Edit Post</span>
{{/link-to}}
<a class="post-settings" title="Post Settings" {{action 'editSettings'}}><span class="hidden">Post Settings</span></a>
<!-- @TODO use Ghost Popover (#2565) --->
{{view "post-settings-menu-view"}}
{{#gh-popover-button popoverName="post-settings-menu" tagName="a" classNames="post-settings" title="Post Settings"}}
<span class="hidden">Post Settings</span>
{{/gh-popover-button}}
{{#gh-popover name="post-settings-menu" classNames="post-settings-menu menu-drop-right"}}
{{view "post-settings-menu-view"}}
{{/gh-popover}}
</section>
</header>

View file

@ -9,23 +9,21 @@
{{gh-activating-list-item route="settings" title="Settings" classNames="settings"}}
<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}}
<img class="avatar" {{bind-attr src="user.image"}} alt="Avatar" />
{{else}}
<img class="avatar" src="/shared/img/user-image.png" alt="Avatar" />
{{/if}}
<span class="name">{{user.name}}</span>
</a>
{{/gh-popover-button}}
{{!-- @TODO: add functionality to allow for dropdown to work --}}
{{#gh-popover open=showMenu}}
<ul class="overlay">
{{#gh-popover tagName="ul" classNames="overlay" name="user-menu" closeOnClick="true"}}
<li class="usermenu-profile">{{#link-to 'settings.user'}}Your Profile{{/link-to}}</li>
<li class="divider"></li>
<li class="usermenu-help"><a href="http://ghost.org/forum/">Help / Support</a></li>
<li class="divider"></li>
<li class="usermenu-signout"><a href="#">Sign Out</a></li>
</ul>
{{/gh-popover}}
</li>
</ul>

View file

@ -14,9 +14,12 @@
<div class="right">
<section id="entry-controls">
<a class="post-settings" title="Post Settings" {{action 'editSettings'}}><span class="hidden">Post Settings</span></a>
<!-- @TODO Use Ghost Popover (#2565) and style arrow down -->
{{view "post-settings-menu-view"}}
{{#gh-popover-button popoverName="post-settings-menu" tagName="a" href="#" classNames="post-settings" title="Post Settings"}}
<span class="hidden">Post Settings</span>
{{/gh-popover-button}}
{{#gh-popover name="post-settings-menu" classNames="post-settings-menu menu-right"}}
{{view "post-settings-menu-view"}}
{{/gh-popover}}
</section>
{{view "editor-save-button" id="entry-actions"}}

View file

@ -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 {{action 'viewSaveTypes'}} {{bind-attr class="controller.isViewingSaveTypes:active :options :up" }} title="Post Settings"><span class="hidden">Post Settings</span>
<button type="button" {{action "save"}} {{bind-attr class="view.isDangerous:button-delete:button-save :js-publish-button" }}>
{{view.save-text}}
</button>
{{!-- @TODO: implement popover --}}
<ul {{bind-attr class="controller.isViewingSaveTypes::hidden :editor-options :overlay" }}>
<li {{bind-attr class="controller.willPublish:active"}}>
<a {{action "setSaveType" "publish"}} href="#">{{view.publish-text}}</a>
{{#gh-popover-button popoverName="post-save-menu" classNameBindings="open:active :options :up" title="Post Settings"}}
<span class="hidden">Post Settings</span>
{{/gh-popover-button}}
{{#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 {{bind-attr class="controller.willPublish::active"}}>
<a {{action "setSaveType" "draft"}} href="#">{{view.draft-text}}</a>
<li {{bind-attr class="controller.willPublish::active" }}>
<a {{action "setSaveType" "draft"}} href="#">{{view.draftText}}</a>
</li>
</ul>
{{/gh-popover}}

View file

@ -3,13 +3,7 @@ import {formatDate} from 'ghost/utils/date-formatting';
var PostSettingsMenuView = Ember.View.extend({
templateName: 'post-settings-menu',
classNames: ['post-settings-menu', 'menu-drop-right', 'overlay'],
classNameBindings: ['controller.isEditingSettings::hidden'],
publishedAtBinding: Ember.Binding.oneWay('controller.publishedAt'),
click: function (event) {
//Stop click propagation to prevent window closing
event.stopPropagation();
},
datePlaceholder: function () {
return formatDate(moment());
}.property('controller.publishedAt')