Refactor: Move initialization code into separate initializers that use the API we

developed for plugins.
This commit is contained in:
Robin Ward 2013-12-03 14:22:32 -05:00
parent de78ee302a
commit 274743b877
14 changed files with 219 additions and 189 deletions

View file

@ -11,9 +11,6 @@
Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
rootElement: '#main',
// Whether the app has focus or not
hasFocus: true,
// Helps with integration tests
URL_FIXTURES: {},
@ -69,61 +66,6 @@ Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
this.set('notifyCount', count);
},
/**
Establishes global DOM events and bindings via jQuery.
@method bindDOMEvents
**/
bindDOMEvents: function() {
$('#main').on('click.discourse', 'a', function(e) {
if (e.isDefaultPrevented() || e.shiftKey || e.metaKey || e.ctrlKey) { return; }
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;
}
e.preventDefault();
Discourse.URL.routeTo(href);
return false;
});
$(window).focus(function() {
Discourse.set('hasFocus', true);
Discourse.set('notify', false);
}).blur(function() {
Discourse.set('hasFocus', false);
});
// Add a CSRF token to all AJAX requests
Discourse.csrfToken = $('meta[name=csrf-token]').attr('content');
$.ajaxPrefilter(function(options, originalOptions, xhr) {
if (!options.crossDomain) {
xhr.setRequestHeader('X-CSRF-Token', Discourse.csrfToken);
}
});
bootbox.animate(false);
bootbox.backdrop(true); // clicking outside a bootbox modal closes it
Discourse.Mobile.init();
setInterval(function(){
Discourse.Formatter.updateRelativeAge($('.relative-date'));
},60 * 1000);
},
/**
Log the current user out of Discourse
@ -153,37 +95,6 @@ Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
if(this.get('loginRequired')) { route.transitionTo('login'); }
},
/**
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;
bus.baseUrl = Discourse.getURL("/");
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){
var site = Discourse.Site.current();
_.each(data.categories,function(c){
site.updateCategory(c);
});
});
}
},
/**
Add an initializer hook for after the Discourse Application starts up.
@ -196,24 +107,16 @@ Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
},
/**
Start up the Discourse application.
Start up the Discourse application by running all the initializers we've defined.
@method start
**/
start: function() {
Discourse.bindDOMEvents();
Discourse.MessageBus.alwaysLongPoll = Discourse.Environment === "development";
Discourse.MessageBus.start();
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus);
// Developer specific functions
Discourse.Development.observeLiveChanges();
Discourse.subscribeUserToNotifications();
if (Discourse.initializers) {
var initializers = this.initializers;
if (initializers) {
var self = this;
Em.run.next(function() {
Discourse.initializers.forEach(function (init) {
initializers.forEach(function (init) {
init.call(self);
});
});

View file

@ -0,0 +1,8 @@
/**
Initialize the message bus to receive messages.
**/
Discourse.addInitializer(function() {
Discourse.MessageBus.alwaysLongPoll = Discourse.Environment === "development";
Discourse.MessageBus.start();
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus);
});

View file

@ -0,0 +1,11 @@
/**
Default settings for bootbox
**/
Discourse.addInitializer(function() {
bootbox.animate(false);
// clicking outside a bootbox modal closes it
bootbox.backdrop(true);
});

View file

@ -0,0 +1,32 @@
/**
Discourse does some server side rendering of HTML, such as the `cooked` contents of
posts. The downside of this in an Ember app is the links will not go through the router.
This jQuery code intercepts clicks on those links and routes them properly.
**/
Discourse.addInitializer(function() {
$('#main').on('click.discourse', 'a', function(e) {
if (e.isDefaultPrevented() || e.shiftKey || e.metaKey || e.ctrlKey) { return; }
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;
}
e.preventDefault();
Discourse.URL.routeTo(href);
return false;
});
});

View file

@ -0,0 +1,19 @@
/**
Append our CSRF token to AJAX requests when necessary.
**/
Discourse.addInitializer(function() {
var session = Discourse.Session;
// Add a CSRF token to all AJAX requests
session.currentProp('csrfToken', $('meta[name=csrf-token]').attr('content'));
$.ajaxPrefilter(function(options, originalOptions, xhr) {
if (!options.crossDomain) {
xhr.setRequestHeader('X-CSRF-Token', session.currentProp('csrfToken'));
}
});
});

View file

@ -0,0 +1,16 @@
/**
Keep track of when the browser is in focus.
**/
Discourse.addInitializer(function() {
// Default to true
this.set('hasFocus', true);
var self = this;
$(window).focus(function() {
self.setProperties({hasFocus: true, notify: false});
}).blur(function() {
self.set('hasFocus', false);
});
});

View file

@ -0,0 +1,7 @@
/**
Initializes the `Discourse.Mobile` helper object.
**/
Discourse.addInitializer(function() {
Discourse.Mobile.init();
});

View file

@ -0,0 +1,73 @@
/**
Use the message bus for live reloading of components for faster development.
**/
Discourse.addInitializer(function() {
console.log('live reloading');
// subscribe to any site customizations that are loaded
$('link.custom-css').each(function() {
var split = this.href.split("/"),
id = split[split.length - 1].split(".css")[0],
self = this;
return Discourse.MessageBus.subscribe("/file-change/" + id, function(data) {
if (!$(self).data('orig')) {
$(self).data('orig', self.href);
}
var orig = $(self).data('orig'),
sp = orig.split(".css?");
self.href = sp[0] + ".css?" + data;
});
});
// Custom header changes
$('header.custom').each(function() {
var header = $(this);
return Discourse.MessageBus.subscribe("/header-change/" + $(this).data('key'), function(data) {
return header.html(data);
});
});
// Observe file changes
return Discourse.MessageBus.subscribe("/file-change", function(data) {
Ember.TEMPLATES.empty = Handlebars.compile("<div></div>");
_.each(data,function(me,idx) {
if (me === "refresh") {
// Refresh if necessary
document.location.reload(true);
} else if (me.name.substr(-10) === "handlebars") {
// Reload handlebars
var js = me.name.replace(".handlebars", "").replace("app/assets/javascripts", "/assets");
$LAB.script(js + "?hash=" + me.hash).wait(function() {
var templateName;
templateName = js.replace(".js", "").replace("/assets/", "");
return _.each(Ember.View.views, function(view) {
if (view.get('templateName') === templateName) {
view.set('templateName', 'empty');
view.rerender();
Em.run.schedule('afterRender', function() {
view.set('templateName', templateName);
view.rerender();
});
}
});
});
} else {
$('link').each(function() {
if (this.href.match(me.name) && me.hash) {
if (!$(this).data('orig')) {
$(this).data('orig', this.href);
}
this.href = $(this).data('orig') + "&hash=" + me.hash;
}
});
}
});
});
});

View file

@ -0,0 +1,12 @@
/**
Updates the relative ages of dates on the screen.
**/
Discourse.addInitializer(function() {
setInterval(function(){
Discourse.Formatter.updateRelativeAge($('.relative-date'));
}, 60 * 1000);
});

View file

@ -0,0 +1,32 @@
/**
Updates the relative ages of dates on the screen.
**/
Discourse.addInitializer(function() {
var user = Discourse.User.current();
if (user) {
var bus = Discourse.MessageBus;
bus.callbackInterval = Discourse.SiteSettings.polling_interval;
bus.enableLongPolling = true;
bus.baseUrl = Discourse.getURL("/");
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){
var site = Discourse.Site.current();
_.each(data.categories,function(c){
site.updateCategory(c);
});
});
}
});

View file

@ -1,81 +0,0 @@
/**
Functions to help development of Discourse, such as inserting probes
@class Development
@namespace Discourse
@module Discourse
**/
Discourse.Development = {
/**
Use the message bus for live reloading of components for faster development.
@method observeLiveChanges
**/
observeLiveChanges: function() {
// subscribe to any site customizations that are loaded
$('link.custom-css').each(function() {
var id, split, stylesheet,
_this = this;
split = this.href.split("/");
id = split[split.length - 1].split(".css")[0];
stylesheet = this;
return Discourse.MessageBus.subscribe("/file-change/" + id, function(data) {
var orig, sp;
if (!$(stylesheet).data('orig')) {
$(stylesheet).data('orig', stylesheet.href);
}
orig = $(stylesheet).data('orig');
sp = orig.split(".css?");
stylesheet.href = sp[0] + ".css?" + data;
});
});
// Custom header changes
$('header.custom').each(function() {
var header;
header = $(this);
return Discourse.MessageBus.subscribe("/header-change/" + ($(this).data('key')), function(data) {
return header.html(data);
});
});
// Observe file changes
return Discourse.MessageBus.subscribe("/file-change", function(data) {
Ember.TEMPLATES.empty = Handlebars.compile("<div></div>");
_.each(data,function(me,idx) {
var js;
if (me === "refresh") {
return document.location.reload(true);
} else if (me.name.substr(-10) === "handlebars") {
js = me.name.replace(".handlebars", "").replace("app/assets/javascripts", "/assets");
return $LAB.script(js + "?hash=" + me.hash).wait(function() {
var templateName;
templateName = js.replace(".js", "").replace("/assets/", "");
return _.each(Ember.View.views, function(view) {
if (view.get('templateName') === templateName) {
view.set('templateName', 'empty');
view.rerender();
Em.run.schedule('afterRender', function() {
view.set('templateName', templateName);
view.rerender();
});
}
});
});
} else {
return $('link').each(function() {
if (this.href.match(me.name) && me.hash) {
if (!$(this).data('orig')) {
$(this).data('orig', this.href);
}
this.href = $(this).data('orig') + "&hash=" + me.hash;
}
});
}
});
});
}
};

View file

@ -1,12 +1,10 @@
/**
A class that is responsible for logic related to mobile devices.
An object that is responsible for logic related to mobile devices.
@class Mobile
@namespace Discourse
@module Discourse
@module Mobile
**/
Discourse.Mobile = {
isMobileDevice: false,
mobileView: false,

View file

@ -59,7 +59,7 @@ Discourse.Ajax = Em.Mixin.create({
// note: for bad CSRF we don't loop an extra request right away.
// this allows us to eliminate the possibility of having a loop.
if (xhr.status === 403 && xhr.responseText === "['BAD CSRF']") {
Discourse.csrfToken = null;
Discourse.Session.current().set('csrfToken', null);
}
// If it's a parseerror, don't reject
@ -79,7 +79,7 @@ Discourse.Ajax = Em.Mixin.create({
// For cached pages we strip out CSRF tokens, need to round trip to server prior to sending the
// request (bypass for GET, not needed)
if(args.type && args.type !== 'GET' && !Discourse.csrfToken){
if(args.type && args.type !== 'GET' && !Discourse.Session.currentProp('csrfToken')){
return Ember.Deferred.promise(function(promise){
$.ajax(Discourse.getURL('/session/csrf'))
.success(function(result){

View file

@ -104,7 +104,7 @@ d.write('<style>#ember-testing-container { position: absolute; background: white
Discourse.rootElement = '#ember-testing';
Discourse.setupForTesting();
Discourse.injectTestHelpers();
Discourse.bindDOMEvents();
Discourse.runInitializers();
Discourse.Router.map(function() {
Discourse.routeBuilder.call(this);