2013-02-06 03:16:51 +08:00
|
|
|
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: (->
|
|
|
|
logo = Discourse.SiteSettings.logo_small_url
|
|
|
|
if logo && logo.length > 1
|
|
|
|
"<img src='#{logo}' width='33' height='33'>"
|
|
|
|
else
|
|
|
|
"<i class='icon-home'></i>"
|
|
|
|
).property()
|
|
|
|
|
|
|
|
titleChanged: (->
|
|
|
|
title = ""
|
|
|
|
title += "#{@get('title')} - " if @get('title')
|
|
|
|
title += Discourse.SiteSettings.title
|
|
|
|
$('title').text(title)
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
title = ("(*) " + title) if !@get('hasFocus') && @get('notify')
|
|
|
|
|
|
|
|
# chrome bug workaround see: http://stackoverflow.com/questions/2952384/changing-the-window-title-when-focussing-the-window-doesnt-work-in-chrome
|
|
|
|
window.setTimeout (->
|
|
|
|
document.title = "."
|
|
|
|
document.title = title
|
|
|
|
return), 200
|
|
|
|
return
|
|
|
|
).observes('title', 'hasFocus', 'notify')
|
|
|
|
|
|
|
|
currentUserChanged: (->
|
|
|
|
|
|
|
|
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
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
user = @get('currentUser')
|
|
|
|
if user
|
|
|
|
bus.callbackInterval = Discourse.SiteSettings.polling_interval
|
|
|
|
bus.enableLongPolling = true
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
if user.admin
|
|
|
|
bus.subscribe "/flagged_counts", (data) ->
|
|
|
|
user.set('site_flagged_posts_count', data.total)
|
|
|
|
bus.subscribe "/notification", ((data) ->
|
|
|
|
user.set('unread_notifications', data.unread_notifications)
|
|
|
|
user.set('unread_private_messages', data.unread_private_messages)), user.notification_channel_position
|
|
|
|
|
|
|
|
).observes('currentUser')
|
|
|
|
|
|
|
|
notifyTitle: ->
|
|
|
|
@set('notify', true)
|
|
|
|
|
|
|
|
# Browser aware replaceState
|
|
|
|
replaceState: (path) ->
|
|
|
|
if window.history && window.history.pushState && window.history.replaceState && !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)
|
|
|
|
history.replaceState({path: path}, null, path) unless window.location.pathname is path
|
|
|
|
|
|
|
|
openComposer: (opts) ->
|
|
|
|
# TODO, remove container link
|
|
|
|
Discourse.__container__.lookup('controller:composer')?.open(opts)
|
|
|
|
|
|
|
|
# Like router.route, but allow full urls rather than relative ones
|
|
|
|
# HERE BE HACKS - uses the ember container for now until we can do this nicer.
|
|
|
|
routeTo: (path) ->
|
|
|
|
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?[2]
|
|
|
|
oldMatches = topicRegexp.exec(window.location.pathname);
|
|
|
|
if (oldTopicId = oldMatches?[2]) && (oldTopicId is newTopicId)
|
|
|
|
Discourse.replaceState(path)
|
|
|
|
topicController = Discourse.__container__.lookup('controller:topic')
|
|
|
|
opts = {trackVisit: false}
|
|
|
|
opts.nearPost = newMatches[3] if newMatches[3]
|
|
|
|
topicController.get('content').loadPosts(opts)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
# Be wary of looking up the router. In this case, we have links in our
|
2013-02-07 23:45:24 +08:00
|
|
|
# HTML, say form compiled markdown posts, that need to be routed.
|
|
|
|
router = Discourse.__container__.lookup('router:main')
|
|
|
|
router.router.updateURL(path)
|
2013-02-06 03:16:51 +08:00
|
|
|
router.handleURL(path)
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
# Scroll to the top if we're not replacing state
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
# The classes of buttons to show on a post
|
|
|
|
postButtons: (->
|
|
|
|
Discourse.SiteSettings.post_menu.split("|").map (i) -> "#{i.replace(/\+/, '').capitalize()}"
|
|
|
|
).property('Discourse.SiteSettings.post_menu')
|
|
|
|
|
|
|
|
bindDOMEvents: ->
|
|
|
|
|
|
|
|
$html = $('html')
|
|
|
|
# Add the discourse touch event
|
|
|
|
hasTouch = false
|
|
|
|
hasTouch = true if $html.hasClass('touch')
|
|
|
|
hasTouch = true if (Modernizr.prefixed("MaxTouchPoints", navigator) > 1)
|
|
|
|
|
|
|
|
if hasTouch
|
|
|
|
$html.addClass('discourse-touch')
|
|
|
|
@touch = true
|
|
|
|
@hasTouch = true
|
|
|
|
else
|
|
|
|
$html.addClass('discourse-no-touch')
|
|
|
|
@touch = false
|
|
|
|
|
|
|
|
$('#main').on 'click.discourse', '[data-not-implemented=true]', (e) =>
|
|
|
|
e.preventDefault()
|
|
|
|
alert Em.String.i18n('not_implemented')
|
|
|
|
false
|
|
|
|
|
|
|
|
$('#main').on 'click.discourse', 'a', (e) =>
|
|
|
|
|
|
|
|
return if (e.isDefaultPrevented() || e.metaKey || e.ctrlKey)
|
|
|
|
$currentTarget = $(e.currentTarget)
|
|
|
|
|
|
|
|
href = $currentTarget.attr('href')
|
|
|
|
return if href is undefined
|
|
|
|
return if href is '#'
|
|
|
|
return if $currentTarget.attr('target')
|
|
|
|
return if $currentTarget.data('auto-route')
|
|
|
|
return if href.indexOf("mailto:") is 0
|
|
|
|
|
|
|
|
if href.match(/^http[s]?:\/\//i) && !href.match new RegExp("^http:\\/\\/" + window.location.hostname,"i")
|
|
|
|
return
|
|
|
|
|
|
|
|
e.preventDefault()
|
|
|
|
@routeTo(href)
|
|
|
|
|
|
|
|
false
|
|
|
|
|
|
|
|
$(window).focus( =>
|
|
|
|
@set('hasFocus',true)
|
|
|
|
@set('notify',false)
|
|
|
|
).blur( =>
|
|
|
|
@set('hasFocus',false)
|
|
|
|
)
|
|
|
|
|
|
|
|
logout: ->
|
|
|
|
username = @get('currentUser.username')
|
|
|
|
Discourse.KeyValueStore.abandonLocal()
|
|
|
|
$.ajax "/session/#{username}",
|
|
|
|
type: 'DELETE'
|
|
|
|
success: (result) =>
|
|
|
|
# To keep lots of our variables unbound, we can handle a redirect on logging out.
|
|
|
|
window.location.reload()
|
|
|
|
|
|
|
|
# fancy probes in ember
|
|
|
|
insertProbes: ->
|
|
|
|
|
|
|
|
return unless console?
|
|
|
|
|
|
|
|
topLevel = (fn,name) ->
|
|
|
|
window.probes.measure fn,
|
|
|
|
name: name
|
|
|
|
before: (data,owner, args) ->
|
|
|
|
if owner
|
|
|
|
window.probes.clear()
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
after: (data, owner, args) ->
|
|
|
|
if owner && data.time > 10
|
|
|
|
f = (name,data) ->
|
|
|
|
"#{name} - #{data.count} calls #{(data.time + 0.0).toFixed(2)}ms" if data && data.count
|
|
|
|
|
|
|
|
if console && console.group
|
|
|
|
console.group(f(name, data))
|
|
|
|
else
|
|
|
|
console.log("")
|
|
|
|
console.log(f(name,data))
|
|
|
|
|
|
|
|
ary = []
|
|
|
|
for n,v of window.probes
|
|
|
|
continue if n == name || v.time < 1
|
|
|
|
ary.push(k: n, v: v)
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
ary.sortBy((item) -> if item.v && item.v.time then -item.v.time else 0).each (item)->
|
|
|
|
console.log output if output = f("#{item.k}", item.v)
|
|
|
|
console?.groupEnd?()
|
|
|
|
|
|
|
|
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")
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
authenticationComplete: (options)->
|
|
|
|
# TODO, how to dispatch this to the view without the container?
|
|
|
|
loginView = Discourse.__container__.lookup('controller:modal').get('currentView')
|
|
|
|
loginView.authenticationComplete(options)
|
|
|
|
|
|
|
|
buildRoutes: (builder) ->
|
|
|
|
oldBuilder = Discourse.routeBuilder
|
|
|
|
Discourse.routeBuilder = ->
|
|
|
|
oldBuilder.call(@) if oldBuilder
|
|
|
|
builder.call(@)
|
|
|
|
|
|
|
|
start: ->
|
|
|
|
@bindDOMEvents()
|
|
|
|
Discourse.SiteSettings = PreloadStore.getStatic('siteSettings')
|
|
|
|
Discourse.MessageBus.start()
|
|
|
|
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus)
|
|
|
|
Discourse.insertProbes()
|
|
|
|
|
2013-02-07 23:45:24 +08:00
|
|
|
|
|
|
|
# subscribe to any site customizations that are loaded
|
2013-02-06 03:16:51 +08:00
|
|
|
$('link.custom-css').each ->
|
|
|
|
split = @href.split("/")
|
|
|
|
id = split[split.length-1].split(".css")[0]
|
|
|
|
stylesheet = @
|
|
|
|
Discourse.MessageBus.subscribe "/file-change/#{id}", (data)=>
|
|
|
|
$(stylesheet).data('orig', stylesheet.href) unless $(stylesheet).data('orig')
|
|
|
|
orig = $(stylesheet).data('orig')
|
|
|
|
sp = orig.split(".css?")
|
|
|
|
stylesheet.href = sp[0] + ".css?" + data
|
|
|
|
|
|
|
|
$('header.custom').each ->
|
|
|
|
header = $(this)
|
|
|
|
Discourse.MessageBus.subscribe "/header-change/#{$(@).data('key')}", (data)->
|
|
|
|
header.html(data)
|
|
|
|
|
|
|
|
# possibly move this to dev only
|
|
|
|
Discourse.MessageBus.subscribe "/file-change", (data)->
|
|
|
|
Ember.TEMPLATES["empty"] = Handlebars.compile("")
|
|
|
|
data.each (me)->
|
|
|
|
if me == "refresh"
|
|
|
|
document.location.reload(true)
|
|
|
|
else if me.name.substr(-10) == "handlebars"
|
|
|
|
js = me.name.replace(".handlebars","").replace("app/assets/javascripts","/assets")
|
|
|
|
$LAB.script(js + "?hash=" + me.hash).wait ->
|
|
|
|
templateName = js.replace(".js","").replace("/assets/","")
|
|
|
|
$.each Ember.View.views, ->
|
|
|
|
if(@get('templateName')==templateName)
|
|
|
|
@set('templateName','empty')
|
|
|
|
@rerender()
|
|
|
|
Em.run.next =>
|
|
|
|
@set('templateName', templateName)
|
|
|
|
@rerender()
|
|
|
|
else
|
|
|
|
$('link').each ->
|
2013-02-06 04:59:17 +08:00
|
|
|
if @href.match(me.name) and me.hash
|
|
|
|
$(@).data('orig', @href) unless $(@).data('orig')
|
|
|
|
@href = $(@).data('orig') + "&hash=" + me.hash
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
window.Discourse.Router = Discourse.Router.reopen(location: 'discourse_location')
|
|
|
|
|
|
|
|
# since we have no jquery-rails these days, hook up csrf token
|
|
|
|
csrf_token = $('meta[name=csrf-token]').attr('content')
|
|
|
|
|
|
|
|
$.ajaxPrefilter (options,originalOptions,xhr) ->
|
|
|
|
unless options.crossDomain
|
|
|
|
xhr.setRequestHeader('X-CSRF-Token', csrf_token)
|
|
|
|
return
|
|
|
|
|