/*global Modernizr:true*/ (function() { var csrf_token; window.Discourse = Ember.Application.createWithMixins({ rootElement: '#main', // Data we want to remember for a short period transient: Em.Object.create(), hasFocus: true, scrolling: false, // The highest seen post number by topic highestSeenByTopic: {}, logoSmall: (function() { var logo; logo = Discourse.SiteSettings.logo_small_url; if (logo && logo.length > 1) { return ""; } else { return ""; } }).property(), titleChanged: (function() { var title; title = ""; if (this.get('title')) { title += "" + (this.get('title')) + " - "; } title += Discourse.SiteSettings.title; jQuery('title').text(title); if (!this.get('hasFocus') && this.get('notify')) { title = "(*) " + title; } // chrome bug workaround see: http://stackoverflow.com/questions/2952384/changing-the-window-title-when-focussing-the-window-doesnt-work-in-chrome window.setTimeout((function() { document.title = "."; document.title = title; }), 200); }).observes('title', 'hasFocus', 'notify'), currentUserChanged: (function() { var bus, user; bus = Discourse.MessageBus; // We don't want to receive any previous user notidications bus.unsubscribe("/notification"); bus.callbackInterval = Discourse.SiteSettings.anon_polling_interval; bus.enableLongPolling = false; user = this.get('currentUser'); if (user) { bus.callbackInterval = Discourse.SiteSettings.polling_interval; bus.enableLongPolling = true; if (user.admin) { bus.subscribe("/flagged_counts", function(data) { return user.set('site_flagged_posts_count', data.total); }); } return bus.subscribe("/notification", (function(data) { user.set('unread_notifications', data.unread_notifications); return user.set('unread_private_messages', data.unread_private_messages); }), user.notification_channel_position); } }).observes('currentUser'), notifyTitle: function() { return this.set('notify', true); }, // Browser aware replaceState replaceState: function(path) { if (window.history && window.history.pushState && window.history.replaceState && !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)) { if (window.location.pathname !== path) { return history.replaceState({ path: path }, null, path); } } }, openComposer: function(opts) { // TODO, remove container link var composer = Discourse.__container__.lookup('controller:composer'); if (composer) composer.open(opts); }, // Like router.route, but allow full urls rather than relative one // HERE BE HACKS - uses the ember container for now until we can do this nicer. routeTo: function(path) { var newMatches, newTopicId, oldMatches, oldTopicId, opts, router, topicController, topicRegexp; path = path.replace(/https?\:\/\/[^\/]+/, ''); // If we're in the same topic, don't push the state topicRegexp = /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/; newMatches = topicRegexp.exec(path); if (newTopicId = newMatches ? newMatches[2] : void 0) { oldMatches = topicRegexp.exec(window.location.pathname); if ((oldTopicId = oldMatches ? oldMatches[2] : void 0) && (oldTopicId === newTopicId)) { Discourse.replaceState(path); topicController = Discourse.__container__.lookup('controller:topic'); opts = { trackVisit: false }; if (newMatches[3]) { opts.nearPost = newMatches[3]; } topicController.get('content').loadPosts(opts); return; } } // Be wary of looking up the router. In this case, we have links in our // HTML, say form compiled markdown posts, that need to be routed. router = Discourse.__container__.lookup('router:main'); router.router.updateURL(path); return router.handleURL(path); }, // 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'), bindDOMEvents: function() { var $html, hasTouch, _this = this; $html = jQuery('html'); /* Add the discourse touch event */ hasTouch = false; if ($html.hasClass('touch')) { hasTouch = true; } if (Modernizr.prefixed("MaxTouchPoints", navigator) > 1) { hasTouch = true; } if (hasTouch) { $html.addClass('discourse-touch'); this.touch = true; this.hasTouch = true; } else { $html.addClass('discourse-no-touch'); this.touch = false; } jQuery('#main').on('click.discourse', '[data-not-implemented=true]', function(e) { e.preventDefault(); alert(Em.String.i18n('not_implemented')); return false; }); jQuery('#main').on('click.discourse', 'a', function(e) { var $currentTarget, href; if (e.isDefaultPrevented() || e.metaKey || e.ctrlKey) { return; } $currentTarget = jQuery(e.currentTarget); href = $currentTarget.attr('href'); if (href === void 0) { return; } if (href === '#') { return; } if ($currentTarget.attr('target')) { return; } if ($currentTarget.data('auto-route')) { return; } if ($currentTarget.hasClass('lightbox')) { return; } if (href.indexOf("mailto:") === 0) { return; } if (href.match(/^http[s]?:\/\//i) && !href.match(new RegExp("^http:\\/\\/" + window.location.hostname, "i"))) { return; } e.preventDefault(); _this.routeTo(href); return false; }); return jQuery(window).focus(function() { _this.set('hasFocus', true); return _this.set('notify', false); }).blur(function() { return _this.set('hasFocus', false); }); }, logout: function() { var username, _this = this; username = this.get('currentUser.username'); Discourse.KeyValueStore.abandonLocal(); return jQuery.ajax("/session/" + username, { type: 'DELETE', success: function(result) { /* To keep lots of our variables unbound, we can handle a redirect on logging out. */ return window.location.reload(); } }); }, /* fancy probes in ember */ insertProbes: function() { var topLevel; if (typeof console === "undefined" || console === null) { return; } topLevel = function(fn, name) { return window.probes.measure(fn, { name: name, before: function(data, owner, args) { if (owner) { return window.probes.clear(); } }, after: function(data, owner, args) { var ary, f, n, v, _ref; if (owner && data.time > 10) { f = function(name, data) { if (data && data.count) { return "" + name + " - " + data.count + " calls " + ((data.time + 0.0).toFixed(2)) + "ms"; } }; if (console && console.group) { console.group(f(name, data)); } else { console.log(""); console.log(f(name, data)); } ary = []; _ref = window.probes; for (n in _ref) { v = _ref[n]; if (n === name || v.time < 1) { continue; } ary.push({ k: n, v: v }); } ary.sortBy(function(item) { if (item.v && item.v.time) { return -item.v.time; } else { return 0; } }).each(function(item) { var output; if (output = f("" + item.k, item.v)) { return console.log(output); } }); if (typeof console !== "undefined" && console !== null) { if (typeof console.groupEnd === "function") { console.groupEnd(); } } return window.probes.clear(); } } }); }; Ember.View.prototype.renderToBuffer = window.probes.measure(Ember.View.prototype.renderToBuffer, "renderToBuffer"); Discourse.routeTo = topLevel(Discourse.routeTo, "Discourse.routeTo"); Ember.run.end = topLevel(Ember.run.end, "Ember.run.end"); }, authenticationComplete: function(options) { // TODO, how to dispatch this to the view without the container? var loginView; loginView = Discourse.__container__.lookup('controller:modal').get('currentView'); return loginView.authenticationComplete(options); }, buildRoutes: function(builder) { var oldBuilder; oldBuilder = Discourse.routeBuilder; Discourse.routeBuilder = function() { if (oldBuilder) { oldBuilder.call(this); } return builder.call(this); } }, start: function() { this.bindDOMEvents(); Discourse.SiteSettings = PreloadStore.getStatic('siteSettings'); Discourse.MessageBus.start(); Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus); Discourse.insertProbes(); // subscribe to any site customizations that are loaded jQuery('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 (!jQuery(stylesheet).data('orig')) { jQuery(stylesheet).data('orig', stylesheet.href); } orig = jQuery(stylesheet).data('orig'); sp = orig.split(".css?"); stylesheet.href = sp[0] + ".css?" + data; }); }); jQuery('header.custom').each(function() { var header; header = jQuery(this); return Discourse.MessageBus.subscribe("/header-change/" + (jQuery(this).data('key')), function(data) { return header.html(data); }); }); // possibly move this to dev only return Discourse.MessageBus.subscribe("/file-change", function(data) { Ember.TEMPLATES.empty = Handlebars.compile("
"); return data.each(function(me) { 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 jQuery.each(Ember.View.views, function() { var _this = this; if (this.get('templateName') === templateName) { this.set('templateName', 'empty'); this.rerender(); return Em.run.next(function() { _this.set('templateName', templateName); return _this.rerender(); }); } }); }); } else { return jQuery('link').each(function() { if (this.href.match(me.name) && me.hash) { if (!jQuery(this).data('orig')) { jQuery(this).data('orig', this.href); } this.href = jQuery(this).data('orig') + "&hash=" + me.hash; } }); } }); }); } }); window.Discourse.Router = Discourse.Router.reopen({ location: 'discourse_location' }); // since we have no jquery-rails these days, hook up csrf token csrf_token = jQuery('meta[name=csrf-token]').attr('content'); jQuery.ajaxPrefilter(function(options, originalOptions, xhr) { if (!options.crossDomain) { xhr.setRequestHeader('X-CSRF-Token', csrf_token); } }); }).call(this);