2013-02-20 13:15:50 -05:00
|
|
|
/*global Modernizr:true*/
|
2013-02-24 19:18:10 -05:00
|
|
|
/*global assetPath:true*/
|
2013-08-18 07:52:13 -04:00
|
|
|
/*global Favcount:true*/
|
2013-02-24 19:18:10 -05:00
|
|
|
|
2013-02-26 14:54:43 -05:00
|
|
|
/**
|
|
|
|
The main Discourse Application
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-02-26 14:54:43 -05:00
|
|
|
@class Discourse
|
|
|
|
@extends Ember.Application
|
|
|
|
**/
|
2013-07-26 15:12:40 -04:00
|
|
|
Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
|
2013-02-22 15:41:12 -05:00
|
|
|
rootElement: '#main',
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-02-26 14:54:43 -05:00
|
|
|
// Whether the app has focus or not
|
2013-02-22 15:41:12 -05:00
|
|
|
hasFocus: true,
|
2013-02-26 14:54:43 -05:00
|
|
|
|
2013-06-20 15:02:02 -04:00
|
|
|
// Helps with integration tests
|
|
|
|
URL_FIXTURES: {},
|
|
|
|
|
2013-03-14 08:01:52 -04:00
|
|
|
getURL: function(url) {
|
2013-05-07 13:30:12 -04:00
|
|
|
// If it's a non relative URL, return it.
|
|
|
|
if (url.indexOf('http') === 0) return url;
|
|
|
|
|
2013-04-03 18:26:47 -04:00
|
|
|
var u = (Discourse.BaseUri === undefined ? "/" : Discourse.BaseUri);
|
2013-03-14 08:01:52 -04:00
|
|
|
if (u[u.length-1] === '/') {
|
|
|
|
u = u.substring(0, u.length-1);
|
|
|
|
}
|
2013-11-12 11:25:27 -05:00
|
|
|
if (url.indexOf(u) !== -1) return url;
|
2013-03-14 08:01:52 -04:00
|
|
|
return u + url;
|
|
|
|
},
|
|
|
|
|
2013-09-16 14:08:55 -04:00
|
|
|
Resolver: Discourse.Resolver,
|
2013-06-03 16:12:24 -04:00
|
|
|
|
2013-02-26 14:54:43 -05:00
|
|
|
titleChanged: function() {
|
2013-07-26 14:59:28 -04:00
|
|
|
var title = "";
|
2013-02-22 15:41:12 -05:00
|
|
|
if (this.get('title')) {
|
|
|
|
title += "" + (this.get('title')) + " - ";
|
|
|
|
}
|
|
|
|
title += Discourse.SiteSettings.title;
|
|
|
|
$('title').text(title);
|
2013-06-02 20:38:57 -04:00
|
|
|
|
|
|
|
var notifyCount = this.get('notifyCount');
|
2013-08-08 12:42:08 -04:00
|
|
|
if (notifyCount > 0 && !Discourse.User.currentProp('dynamic_favicon')) {
|
2013-06-02 20:38:57 -04:00
|
|
|
title = "(" + notifyCount + ") " + title;
|
2013-02-22 15:41:12 -05:00
|
|
|
}
|
|
|
|
// chrome bug workaround see: http://stackoverflow.com/questions/2952384/changing-the-window-title-when-focussing-the-window-doesnt-work-in-chrome
|
2013-02-26 14:54:43 -05:00
|
|
|
window.setTimeout(function() {
|
2013-02-22 15:41:12 -05:00
|
|
|
document.title = ".";
|
|
|
|
document.title = title;
|
2013-02-26 14:54:43 -05:00
|
|
|
}, 200);
|
2013-06-02 20:38:57 -04:00
|
|
|
}.observes('title', 'hasFocus', 'notifyCount'),
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-06-07 20:15:49 -04:00
|
|
|
faviconChanged: function() {
|
2013-08-08 12:42:08 -04:00
|
|
|
if(Discourse.User.currentProp('dynamic_favicon')) {
|
2013-08-18 14:26:03 -04:00
|
|
|
new Favcount(Discourse.SiteSettings.favicon_url).set(
|
|
|
|
this.get('notifyCount')
|
2013-06-07 20:15:49 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}.observes('notifyCount'),
|
|
|
|
|
2013-02-26 14:54:43 -05:00
|
|
|
// The classes of buttons to show on a post
|
|
|
|
postButtons: function() {
|
|
|
|
return Discourse.SiteSettings.post_menu.split("|").map(function(i) {
|
|
|
|
return (i.replace(/\+/, '').capitalize());
|
|
|
|
});
|
|
|
|
}.property('Discourse.SiteSettings.post_menu'),
|
|
|
|
|
2013-06-02 20:38:57 -04:00
|
|
|
notifyTitle: function(count) {
|
|
|
|
this.set('notifyCount', count);
|
2013-02-22 15:41:12 -05:00
|
|
|
},
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-02-26 14:54:43 -05:00
|
|
|
/**
|
|
|
|
Establishes global DOM events and bindings via jQuery.
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-02-26 14:54:43 -05:00
|
|
|
@method bindDOMEvents
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
bindDOMEvents: function() {
|
|
|
|
$('#main').on('click.discourse', 'a', function(e) {
|
2013-07-03 14:06:34 -04:00
|
|
|
if (e.isDefaultPrevented() || e.shiftKey || e.metaKey || e.ctrlKey) { return; }
|
2013-02-26 14:54:43 -05:00
|
|
|
|
2013-10-03 12:51:30 -04:00
|
|
|
var $currentTarget = $(e.currentTarget),
|
|
|
|
href = $currentTarget.attr('href');
|
|
|
|
|
|
|
|
if (!href ||
|
|
|
|
href === '#' ||
|
|
|
|
$currentTarget.attr('target') ||
|
|
|
|
$currentTarget.data('ember-action') ||
|
|
|
|
$currentTarget.data('auto-route') ||
|
|
|
|
$currentTarget.hasClass('ember-view') ||
|
|
|
|
$currentTarget.hasClass('lightbox') ||
|
|
|
|
href.indexOf("mailto:") === 0 ||
|
|
|
|
(href.match(/^http[s]?:\/\//i) && !href.match(new RegExp("^http:\\/\\/" + window.location.hostname, "i")))) {
|
|
|
|
return;
|
|
|
|
}
|
2013-02-26 14:54:43 -05:00
|
|
|
|
2013-02-22 15:41:12 -05:00
|
|
|
e.preventDefault();
|
2013-02-26 14:54:43 -05:00
|
|
|
Discourse.URL.routeTo(href);
|
2013-02-22 15:41:12 -05:00
|
|
|
return false;
|
|
|
|
});
|
2013-02-26 14:54:43 -05:00
|
|
|
|
|
|
|
$(window).focus(function() {
|
|
|
|
Discourse.set('hasFocus', true);
|
|
|
|
Discourse.set('notify', false);
|
2013-02-22 15:41:12 -05:00
|
|
|
}).blur(function() {
|
2013-02-26 14:54:43 -05:00
|
|
|
Discourse.set('hasFocus', false);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Add a CSRF token to all AJAX requests
|
2013-08-27 01:56:12 -04:00
|
|
|
Discourse.csrfToken = $('meta[name=csrf-token]').attr('content');
|
|
|
|
|
2013-03-05 15:39:21 -05:00
|
|
|
$.ajaxPrefilter(function(options, originalOptions, xhr) {
|
2013-02-26 14:54:43 -05:00
|
|
|
if (!options.crossDomain) {
|
2013-08-27 01:56:12 -04:00
|
|
|
xhr.setRequestHeader('X-CSRF-Token', Discourse.csrfToken);
|
2013-02-26 14:54:43 -05:00
|
|
|
}
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
2013-06-04 19:32:03 -04:00
|
|
|
|
2013-06-24 15:00:57 -04:00
|
|
|
bootbox.animate(false);
|
|
|
|
bootbox.backdrop(true); // clicking outside a bootbox modal closes it
|
|
|
|
|
2013-09-10 16:43:51 -04:00
|
|
|
Discourse.Mobile.init();
|
2013-08-27 13:41:36 -04:00
|
|
|
|
2013-06-04 19:32:03 -04:00
|
|
|
setInterval(function(){
|
|
|
|
Discourse.Formatter.updateRelativeAge($('.relative-date'));
|
|
|
|
},60 * 1000);
|
2013-02-22 15:41:12 -05:00
|
|
|
},
|
2013-02-26 14:54:43 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
Log the current user out of Discourse
|
|
|
|
|
|
|
|
@method logout
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
logout: function() {
|
2013-05-28 11:08:32 -04:00
|
|
|
Discourse.User.logout().then(function() {
|
2013-04-03 16:06:55 -04:00
|
|
|
// Reloading will refresh unbound properties
|
2013-05-28 11:08:32 -04:00
|
|
|
Discourse.KeyValueStore.abandonLocal();
|
2013-08-06 16:04:02 -04:00
|
|
|
window.location.pathname = Discourse.getURL('/');
|
2013-06-21 14:06:20 -04:00
|
|
|
});
|
2013-02-22 15:41:12 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
authenticationComplete: function(options) {
|
2013-05-30 14:12:33 -04:00
|
|
|
// TODO, how to dispatch this to the controller without the container?
|
|
|
|
var loginController = Discourse.__container__.lookup('controller:login');
|
|
|
|
return loginController.authenticationComplete(options);
|
2013-02-22 15:41:12 -05:00
|
|
|
},
|
2013-02-26 14:54:43 -05:00
|
|
|
|
2013-06-04 18:37:53 -04:00
|
|
|
loginRequired: function() {
|
|
|
|
return (
|
|
|
|
Discourse.SiteSettings.login_required && !Discourse.User.current()
|
|
|
|
);
|
|
|
|
}.property(),
|
|
|
|
|
2013-06-04 18:39:35 -04:00
|
|
|
redirectIfLoginRequired: function(route) {
|
|
|
|
if(this.get('loginRequired')) { route.transitionTo('login'); }
|
|
|
|
},
|
|
|
|
|
2013-05-28 17:12:37 -04:00
|
|
|
/**
|
|
|
|
Subscribes the current user to receive message bus notifications
|
|
|
|
**/
|
|
|
|
subscribeUserToNotifications: function() {
|
|
|
|
var user = Discourse.User.current();
|
|
|
|
if (user) {
|
|
|
|
var bus = Discourse.MessageBus;
|
|
|
|
bus.callbackInterval = Discourse.SiteSettings.polling_interval;
|
|
|
|
bus.enableLongPolling = true;
|
2013-11-14 00:37:50 -05:00
|
|
|
bus.baseUrl = Discourse.getURL("/");
|
|
|
|
|
2013-05-28 17:12:37 -04:00
|
|
|
if (user.admin || user.moderator) {
|
|
|
|
bus.subscribe("/flagged_counts", function(data) {
|
|
|
|
user.set('site_flagged_posts_count', data.total);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
bus.subscribe("/notification/" + user.get('id'), (function(data) {
|
|
|
|
user.set('unread_notifications', data.unread_notifications);
|
|
|
|
user.set('unread_private_messages', data.unread_private_messages);
|
|
|
|
}), user.notification_channel_position);
|
|
|
|
|
|
|
|
bus.subscribe("/categories", function(data){
|
2013-08-08 12:49:58 -04:00
|
|
|
var site = Discourse.Site.current();
|
2013-06-10 16:48:50 -04:00
|
|
|
_.each(data.categories,function(c){
|
2013-06-21 14:06:20 -04:00
|
|
|
site.updateCategory(c);
|
2013-05-28 17:12:37 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2013-09-19 20:59:17 -04:00
|
|
|
/**
|
|
|
|
Add an initializer hook for after the Discourse Application starts up.
|
|
|
|
|
|
|
|
@method addInitializer
|
|
|
|
@param {Function} init the initializer to add.
|
|
|
|
**/
|
|
|
|
addInitializer: function(init) {
|
|
|
|
Discourse.initializers = Discourse.initializers || [];
|
|
|
|
Discourse.initializers.push(init);
|
|
|
|
},
|
|
|
|
|
2013-04-01 16:28:26 -04:00
|
|
|
/**
|
|
|
|
Start up the Discourse application.
|
|
|
|
|
|
|
|
@method start
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
start: function() {
|
2013-02-26 14:54:43 -05:00
|
|
|
Discourse.bindDOMEvents();
|
2013-04-18 23:06:00 -04:00
|
|
|
Discourse.MessageBus.alwaysLongPoll = Discourse.Environment === "development";
|
2013-02-22 15:41:12 -05:00
|
|
|
Discourse.MessageBus.start();
|
|
|
|
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus);
|
2013-06-02 14:05:12 -04:00
|
|
|
|
2013-02-26 14:54:43 -05:00
|
|
|
// Developer specific functions
|
|
|
|
Discourse.Development.observeLiveChanges();
|
2013-05-28 17:12:37 -04:00
|
|
|
Discourse.subscribeUserToNotifications();
|
2013-09-19 20:59:17 -04:00
|
|
|
|
|
|
|
if (Discourse.initializers) {
|
2013-10-01 13:53:26 -04:00
|
|
|
var self = this;
|
|
|
|
Em.run.next(function() {
|
|
|
|
Discourse.initializers.forEach(function (init) {
|
|
|
|
init.call(self);
|
|
|
|
});
|
2013-09-19 20:59:17 -04:00
|
|
|
});
|
|
|
|
}
|
2013-02-22 15:41:12 -05:00
|
|
|
}
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-03-12 23:06:58 -04:00
|
|
|
Discourse.Router = Discourse.Router.reopen({ location: 'discourse_location' });
|