Refactored SiteMap/Header to support more dynamic flag counts
Also fixes deprecation in `plugin-outlet`
This commit is contained in:
parent
dece5a351a
commit
7c9fb5d3fc
|
@ -1,6 +1,6 @@
|
|||
import DiscourseController from 'discourse/controllers/controller';
|
||||
|
||||
export default DiscourseController.extend({
|
||||
const HeaderController = DiscourseController.extend({
|
||||
topic: null,
|
||||
showExtraInfo: null,
|
||||
notifications: null,
|
||||
|
@ -18,9 +18,9 @@ export default DiscourseController.extend({
|
|||
return Discourse.User.current() && !this.get('topic.isPrivateMessage');
|
||||
}.property('topic.isPrivateMessage'),
|
||||
|
||||
_resetCachedNotifications: function(){
|
||||
_resetCachedNotifications: function() {
|
||||
// a bit hacky, but if we have no focus, hide notifications first
|
||||
var visible = $("#notifications-dropdown").is(":visible");
|
||||
const visible = $("#notifications-dropdown").is(":visible");
|
||||
|
||||
if(!Discourse.get("hasFocus")) {
|
||||
if(visible){
|
||||
|
@ -37,7 +37,7 @@ export default DiscourseController.extend({
|
|||
}.observes("currentUser.lastNotificationChange"),
|
||||
|
||||
refreshNotifications: function(){
|
||||
var self = this;
|
||||
const self = this;
|
||||
if (self.get("loadingNotifications")) { return; }
|
||||
|
||||
self.set("loadingNotifications", true);
|
||||
|
@ -56,14 +56,14 @@ export default DiscourseController.extend({
|
|||
},
|
||||
|
||||
actions: {
|
||||
toggleStar: function() {
|
||||
var topic = this.get('topic');
|
||||
toggleStar() {
|
||||
const topic = this.get('topic');
|
||||
if (topic) topic.toggleStar();
|
||||
return false;
|
||||
},
|
||||
|
||||
showNotifications: function(headerView) {
|
||||
var self = this;
|
||||
showNotifications(headerView) {
|
||||
const self = this;
|
||||
|
||||
if (self.get('currentUser.unread_notifications') || self.get('currentUser.unread_private_messages') || !self.get('notifications')) {
|
||||
self.refreshNotifications();
|
||||
|
@ -71,5 +71,34 @@ export default DiscourseController.extend({
|
|||
headerView.showDropdownBySelector("#user-notifications");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Allow plugins to add to the sum of "flags" above the site map
|
||||
const _flagProperties = [];
|
||||
function addFlagProperty(prop) {
|
||||
_flagProperties.pushObject(prop);
|
||||
}
|
||||
|
||||
let _appliedFlagProps = false;
|
||||
HeaderController.reopenClass({
|
||||
create() {
|
||||
// We only want to change the class the first time it's created
|
||||
if (!_appliedFlagProps && _flagProperties.length) {
|
||||
_appliedFlagProps = true;
|
||||
|
||||
const args = _flagProperties.slice();
|
||||
args.push(function() {
|
||||
let sum = 0;
|
||||
_flagProperties.forEach((fp) => sum += (this.get(fp) || 0));
|
||||
return sum;
|
||||
});
|
||||
HeaderController.reopen({ flaggedPostsCount: Ember.computed.apply(this, args) });
|
||||
}
|
||||
return this._super.apply(this, Array.prototype.slice.call(arguments));
|
||||
}
|
||||
});
|
||||
|
||||
addFlagProperty('currentUser.site_flagged_posts_count');
|
||||
|
||||
export { addFlagProperty };
|
||||
export default HeaderController;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
export default Ember.ArrayController.extend({
|
||||
needs: ['application'],
|
||||
needs: ['application', 'header'],
|
||||
|
||||
showBadgesLink: function(){return Discourse.SiteSettings.enable_badges;}.property(),
|
||||
showAdminLinks: Em.computed.alias('currentUser.staff'),
|
||||
flaggedPostsCount: Em.computed.alias("currentUser.site_flagged_posts_count"),
|
||||
|
||||
faqUrl: function() {
|
||||
return Discourse.SiteSettings.faq_url ? Discourse.SiteSettings.faq_url : Discourse.getURL('/faq');
|
||||
|
|
|
@ -47,25 +47,24 @@
|
|||
|
||||
**/
|
||||
|
||||
var _connectorCache;
|
||||
let _connectorCache;
|
||||
|
||||
function findOutlets(collection, callback) {
|
||||
|
||||
var disabledPlugins = Discourse.Site.currentProp('disabled_plugins') || [];
|
||||
const disabledPlugins = Discourse.Site.currentProp('disabled_plugins') || [];
|
||||
|
||||
Ember.keys(collection).forEach(function(res) {
|
||||
if (res.indexOf("/connectors/") !== -1) {
|
||||
// Skip any disabled plugins
|
||||
for (var i=0; i<disabledPlugins.length; i++) {
|
||||
for (let i=0; i<disabledPlugins.length; i++) {
|
||||
if (res.indexOf("/" + disabledPlugins[i] + "/") !== -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var segments = res.split("/"),
|
||||
outletName = segments[segments.length-2],
|
||||
uniqueName = segments[segments.length-1];
|
||||
|
||||
const segments = res.split("/"),
|
||||
outletName = segments[segments.length-2],
|
||||
uniqueName = segments[segments.length-1];
|
||||
|
||||
callback(outletName, res, uniqueName);
|
||||
}
|
||||
|
@ -75,11 +74,11 @@ function findOutlets(collection, callback) {
|
|||
function buildConnectorCache() {
|
||||
_connectorCache = {};
|
||||
|
||||
var uniqueViews = {};
|
||||
const uniqueViews = {};
|
||||
findOutlets(requirejs._eak_seen, function(outletName, resource, uniqueName) {
|
||||
_connectorCache[outletName] = _connectorCache[outletName] || [];
|
||||
|
||||
var viewClass = require(resource, null, null, true).default;
|
||||
const viewClass = require(resource, null, null, true).default;
|
||||
uniqueViews[uniqueName] = viewClass;
|
||||
_connectorCache[outletName].pushObject(viewClass);
|
||||
});
|
||||
|
@ -87,8 +86,8 @@ function buildConnectorCache() {
|
|||
findOutlets(Ember.TEMPLATES, function(outletName, resource, uniqueName) {
|
||||
_connectorCache[outletName] = _connectorCache[outletName] || [];
|
||||
|
||||
var mixin = {templateName: resource.replace('javascripts/', '')},
|
||||
viewClass = uniqueViews[uniqueName];
|
||||
const mixin = {templateName: resource.replace('javascripts/', '')};
|
||||
let viewClass = uniqueViews[uniqueName];
|
||||
|
||||
if (viewClass) {
|
||||
// We are going to add it back with the proper template
|
||||
|
@ -104,21 +103,24 @@ export default function(connectionName, options) {
|
|||
if (!_connectorCache) { buildConnectorCache(); }
|
||||
|
||||
if (_connectorCache[connectionName]) {
|
||||
var viewClass;
|
||||
var childViews = _connectorCache[connectionName];
|
||||
const childViews = _connectorCache[connectionName];
|
||||
|
||||
// If there is more than one view, create a container. Otherwise
|
||||
// just shove it in.
|
||||
if (childViews.length > 1) {
|
||||
viewClass = Ember.ContainerView.extend({
|
||||
childViews: childViews
|
||||
});
|
||||
} else {
|
||||
viewClass = childViews[0];
|
||||
}
|
||||
const viewClass = (childViews.length > 1) ? Ember.ContainerView : childViews[0];
|
||||
|
||||
delete options.fn; // we don't need the default template since we have a connector
|
||||
return Ember.Handlebars.helpers.view.call(this, viewClass, options);
|
||||
Ember.Handlebars.helpers.view.call(this, viewClass, options);
|
||||
|
||||
const cvs = options.data.view._childViews;
|
||||
if (childViews.length > 1 && cvs && cvs.length) {
|
||||
const inserted = cvs[cvs.length-1];
|
||||
if (inserted) {
|
||||
childViews.forEach(function(cv) {
|
||||
inserted.pushObject(cv.create());
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (options.fn) {
|
||||
// If a block is passed, render its content.
|
||||
return Ember.Handlebars.helpers.view.call(this,
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
var _decorateId = 0;
|
||||
let _decorateId = 0;
|
||||
|
||||
function decorate(klass, evt, cb) {
|
||||
var mixin = {};
|
||||
const mixin = {};
|
||||
mixin["_decorate_" + (_decorateId++)] = function($elem) { cb($elem); }.on(evt);
|
||||
klass.reopen(mixin);
|
||||
}
|
||||
|
||||
export function decorateCooked(container, cb) {
|
||||
var postView = container.lookupFactory('view:post');
|
||||
const postView = container.lookupFactory('view:post');
|
||||
decorate(postView, 'postViewInserted', cb);
|
||||
decorate(postView, 'postViewUpdated', cb);
|
||||
decorate(container.lookupFactory('view:composer'), 'previewRefreshed', cb);
|
||||
|
|
|
@ -52,14 +52,14 @@
|
|||
<a class='icon'
|
||||
data-dropdown="site-map-dropdown"
|
||||
data-render="renderSiteMap"
|
||||
href="#"
|
||||
href
|
||||
title='{{i18n 'site_map'}}'
|
||||
id="site-map">
|
||||
{{fa-icon "bars" label="site_map"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if currentUser.site_flagged_posts_count}}
|
||||
<a href='/admin/flags/active' title='{{i18n 'notifications.total_flagged'}}' class='badge-notification flagged-posts'>{{currentUser.site_flagged_posts_count}}</a>
|
||||
{{#if flaggedPostsCount}}
|
||||
<a href='/admin/flags/active' title='{{i18n 'notifications.total_flagged'}}' class='badge-notification flagged-posts'>{{flaggedPostsCount}}</a>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{#if currentUser}}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
</li>
|
||||
<li>
|
||||
<a href="/admin/flags/active" class="flagged-posts-link">
|
||||
<i class='fa fa-flag'></i> {{i18n 'flags_title'}}
|
||||
{{#if flaggedPostsCount}}
|
||||
<span title='{{i18n 'notifications.total_flagged'}}' class='badge-notification flagged-posts'>{{flaggedPostsCount}}</span>
|
||||
{{fa-icon "flag"}} {{i18n 'flags_title'}}
|
||||
{{#if currentUser.site_flagged_posts_count}}
|
||||
<span title='{{i18n 'notifications.total_flagged'}}' class='badge-notification flagged-posts'>{{currentUser.site_flagged_posts_count}}</span>
|
||||
{{/if}}
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -1,13 +1,4 @@
|
|||
/**
|
||||
This view handles rendering of the header of the site
|
||||
|
||||
@class HeaderView
|
||||
@extends Discourse.View
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
|
||||
var originalZIndex;
|
||||
let originalZIndex;
|
||||
|
||||
export default Discourse.View.extend({
|
||||
tagName: 'header',
|
||||
|
@ -19,7 +10,7 @@ export default Discourse.View.extend({
|
|||
showDropdown: function($target) {
|
||||
var self = this;
|
||||
|
||||
if(!this.get("renderDropdowns")){
|
||||
if (!this.get("renderDropdowns")) {
|
||||
this.set("renderDropdowns", true);
|
||||
Em.run.next(function(){
|
||||
self.showDropdown($target);
|
||||
|
@ -27,30 +18,29 @@ export default Discourse.View.extend({
|
|||
return;
|
||||
}
|
||||
|
||||
var elementId = $target.data('dropdown') || $target.data('notifications'),
|
||||
$dropdown = $("#" + elementId),
|
||||
$li = $target.closest('li'),
|
||||
$ul = $target.closest('ul'),
|
||||
$html = $('html'),
|
||||
$header = $('header'),
|
||||
replyZIndex = parseInt($('#reply-control').css('z-index'), 10);
|
||||
|
||||
const elementId = $target.data('dropdown') || $target.data('notifications'),
|
||||
$dropdown = $("#" + elementId),
|
||||
$li = $target.closest('li'),
|
||||
$ul = $target.closest('ul'),
|
||||
$html = $('html'),
|
||||
$header = $('header'),
|
||||
replyZIndex = parseInt($('#reply-control').css('z-index'), 10);
|
||||
|
||||
originalZIndex = originalZIndex || $('header').css('z-index');
|
||||
|
||||
if(replyZIndex > 0) {
|
||||
if (replyZIndex > 0) {
|
||||
$header.css("z-index", replyZIndex + 1);
|
||||
}
|
||||
|
||||
var controller = self.get('controller');
|
||||
if(controller && !controller.isDestroyed){
|
||||
const controller = self.get('controller');
|
||||
if (controller && !controller.isDestroyed) {
|
||||
controller.set('visibleDropdown', elementId);
|
||||
}
|
||||
// we need to ensure we are rendered,
|
||||
// this optimises the speed of the initial render
|
||||
var render = $target.data('render');
|
||||
if(render){
|
||||
if(!this.get(render)){
|
||||
const render = $target.data('render');
|
||||
if (render){
|
||||
if (!this.get(render)){
|
||||
this.set(render, true);
|
||||
Em.run.next(this, function(){
|
||||
this.showDropdown.apply(self, [$target]);
|
||||
|
@ -59,20 +49,21 @@ export default Discourse.View.extend({
|
|||
}
|
||||
}
|
||||
|
||||
var hideDropdown = function() {
|
||||
const hideDropdown = function() {
|
||||
$header.css("z-index", originalZIndex);
|
||||
$dropdown.fadeOut('fast');
|
||||
$li.removeClass('active');
|
||||
$html.data('hide-dropdown', null);
|
||||
var controller = self.get('controller');
|
||||
if(controller && !controller.isDestroyed){
|
||||
|
||||
const controller = self.get('controller');
|
||||
if (controller && !controller.isDestroyed){
|
||||
controller.set('visibleDropdown', null);
|
||||
}
|
||||
return $html.off('click.d-dropdown');
|
||||
$html.off('click.d-dropdown');
|
||||
};
|
||||
|
||||
// if a dropdown is active and the user clicks on it, close it
|
||||
if($li.hasClass('active')) { return hideDropdown(); }
|
||||
if ($li.hasClass('active')) { return hideDropdown(); }
|
||||
// otherwhise, mark it as active
|
||||
$li.addClass('active');
|
||||
// hide the other dropdowns
|
||||
|
@ -129,16 +120,16 @@ export default Discourse.View.extend({
|
|||
|
||||
},
|
||||
|
||||
willDestroyElement: function() {
|
||||
_tearDown: function() {
|
||||
$(window).unbind('scroll.discourse-dock');
|
||||
$(document).unbind('touchmove.discourse-dock');
|
||||
this.$('a.unread-private-messages, a.unread-notifications, a[data-notifications]').off('click.notifications');
|
||||
this.$('a[data-dropdown]').off('click.dropdown');
|
||||
},
|
||||
}.on('willDestroyElement'),
|
||||
|
||||
didInsertElement: function() {
|
||||
_setup: function() {
|
||||
|
||||
var self = this;
|
||||
const self = this;
|
||||
|
||||
this.$('a[data-dropdown]').on('click.dropdown', function(e) {
|
||||
self.showDropdown.apply(self, [$(e.currentTarget)]);
|
||||
|
@ -172,7 +163,5 @@ export default Discourse.View.extend({
|
|||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}.on('didInsertElement')
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
var oldMobileView;
|
||||
|
||||
moduleFor("controller:site-map", "controller:site-map", {
|
||||
needs: ['controller:application'],
|
||||
needs: ['controller:application', 'controller:header'],
|
||||
|
||||
setup: function() {
|
||||
oldMobileView = Discourse.Mobile.mobileView;
|
||||
|
@ -21,16 +21,6 @@ test("showAdminLinks", function() {
|
|||
equal(controller.get("showAdminLinks"), false, "is false when current user is not a staff member");
|
||||
});
|
||||
|
||||
test("flaggedPostsCount", function() {
|
||||
const currentUser = Ember.Object.create({ site_flagged_posts_count: 5 });
|
||||
const controller = this.subject({ currentUser });
|
||||
|
||||
equal(controller.get("flaggedPostsCount"), 5, "returns current user's flagged posts count");
|
||||
|
||||
currentUser.set("site_flagged_posts_count", 0);
|
||||
equal(controller.get("flaggedPostsCount"), 0, "is bound (reacts to change of current user's flagged posts count)");
|
||||
});
|
||||
|
||||
test("faqUrl returns faq url configured in site settings if it is set", function() {
|
||||
Discourse.SiteSettings.faq_url = "faq-url";
|
||||
var controller = this.subject();
|
||||
|
|
Loading…
Reference in New Issue