Merge branch 'master' into vagrant-chef

This commit is contained in:
Elliot Murphy 2013-02-07 13:58:28 -05:00
commit 9e198c3ac5
235 changed files with 3209 additions and 1173 deletions

View File

@ -2,7 +2,7 @@
## Before You Start
Anyone wishing to contribute to the **[Discourse/Discourse](https://github.com/discourse/discourse)** project **MUST read & sign the [Electronic Discourse Forums Contribution License Agreement](https://docs.google.com/a/discourse.org/spreadsheet/viewform?formkey=dGUwejFfbDhDYXR4bVFMRG1TUENqLWc6MQ)**. The Discourse team is legally prevented from accepting any pull requests from users who have not signed the CLA first.
Anyone wishing to contribute to the **[Discourse/Discourse](https://github.com/discourse/discourse)** project **MUST read & sign the [Electronic Discourse Forums Contribution License Agreement](http://www.discourse.org/cla)**. The Discourse team is legally prevented from accepting any pull requests from users who have not signed the CLA first.
## Reporting Bugs
@ -20,7 +20,7 @@ Anyone wishing to contribute to the **[Discourse/Discourse](https://github.com/d
## Requesting New Features
1. Do not submit a feature request on GitHub; all feature requests on GitHub will be closed. Instead, visit the Discourse development forums, and search for the "Feature Request" category, which will filter a list of outstanding requests. Review this list for similar feature requests. It's possible somebody has already asked for this feature or provided a pull request that we're still discussing.
1. Do not submit a feature request on GitHub; all feature requests on GitHub will be closed. Instead, visit the **[Discourse development forums](http://meta.discourse.org/category/feature)**, and search for the "Feature" category, which will filter a list of outstanding requests. Review this list for similar feature requests. It's possible somebody has already asked for this feature or provided a pull request that we're still discussing.
2. Provide a clear and detailed explanation of the feature you want and why it's important to add. The feature must apply to a wide array of users of Discourse; for smaller, more targeted "one-off" features, you might consider writing a plugin for Discourse. You may also want to provide us with some advance documentation on the feature, which will help the community to better understand where it will fit.

View File

@ -1,5 +1,6 @@
source 'https://rubygems.org'
gem 'slim' # required for sidekiq-web
gem 'redis'
gem 'redis-rails'
gem 'hiredis'

View File

@ -344,7 +344,6 @@ GEM
temple (0.4.1)
terminal-notifier-guard (1.5.3)
terminal-table (1.4.5)
test-unit (2.5.4)
therubyracer (0.11.3)
libv8 (~> 3.11.8.12)
ref
@ -391,7 +390,6 @@ DEPENDENCIES
guard-jasmine
guard-rspec
guard-spork
haml
has_ip_address
hiredis
hpricot
@ -432,9 +430,8 @@ DEPENDENCIES
simple_handlebars_rails!
simplecov
sinatra
slim (<= 1.3.0)
slim
terminal-notifier-guard
test-unit
therubyracer
thin
turbo-sprockets-rails3

View File

@ -6,7 +6,7 @@ window.Discourse.AdminEmailLogsController = Ember.ArrayController.extend Discour
sendTestEmail: ->
@set('sentTestEmail', false)
$.ajax
$.ajax
url: '/admin/email_logs/test',
type: 'POST'
data:
@ -14,4 +14,4 @@ window.Discourse.AdminEmailLogsController = Ember.ArrayController.extend Discour
success: =>
@set('sentTestEmail', true)
false

View File

@ -20,11 +20,11 @@ window.Discourse.AdminSiteSettingsController = Ember.ArrayController.extend Disc
true
).property('filter', 'content.@each', 'onlyOverridden')
resetDefault: (setting) ->
setting.set('value', setting.get('default'))
setting.save()
save: (setting) -> setting.save()
cancel: (setting) -> setting.resetValue()
cancel: (setting) -> setting.resetValue()

View File

@ -12,8 +12,8 @@ window.Discourse.AdminUsersListController = Ember.ArrayController.extend Discour
filterUsers: Discourse.debounce(->
@refreshUsers()
,250).observes('username')
orderChanged: (->
orderChanged: (->
@refreshUsers()
).observes('query')

View File

@ -40,13 +40,13 @@ window.Discourse.AdminUser = Discourse.Model.extend
canBan: ( ->
!@admin && !@moderator
).property('admin','moderator')
banDuration: (->
banned_at = Date.create(@banned_at)
banned_till = Date.create(@banned_till)
"#{banned_at.short()} - #{banned_till.short()}"
).property('banned_till', 'banned_at')
ban: ->
@ -64,7 +64,7 @@ window.Discourse.AdminUser = Discourse.Model.extend
error = Em.String.i18n('admin.user.ban_failed', error: "http: #{e.status} - #{e.body}")
bootbox.alert error
return
unban: ->
$.ajax "/admin/users/#{@id}/unban",
type: 'PUT'
@ -75,7 +75,7 @@ window.Discourse.AdminUser = Discourse.Model.extend
error = Em.String.i18n('admin.user.unban_failed', error: "http: #{e.status} - #{e.body}")
bootbox.alert error
return
impersonate: ->
$.ajax "/admin/impersonate"
type: 'POST'

View File

@ -11,7 +11,7 @@ window.Discourse.EmailLog.reopenClass
$.ajax
url: "/admin/email_logs.json"
data: {filter: filter}
success: (logs) ->
success: (logs) ->
logs.each (log) -> result.pushObject(Discourse.EmailLog.create(log))
result

View File

@ -15,7 +15,7 @@ window.Discourse.FlaggedPost = Discourse.Post.extend
message: a.message
r
).property()
lastFlagged: (->
@post_actions[0].created_at
).property()

View File

@ -45,7 +45,7 @@ window.Discourse.SiteCustomization = Discourse.Model.extend
data:
site_customization: data
type: if @id then 'PUT' else 'POST'
delete: ->
return unless @id
$.ajax

View File

@ -23,19 +23,19 @@ window.Discourse.SiteSetting = Discourse.Model.extend Discourse.Presence,
save: ->
# Update the setting
# Update the setting
$.ajax "/admin/site_settings/#{@get('setting')}",
data:
value: @get('value')
type: 'PUT'
success: => @set('originalValue', @get('value'))
window.Discourse.SiteSetting.reopenClass
findAll: ->
result = Em.A()
findAll: ->
result = Em.A()
$.get "/admin/site_settings", (settings) ->
settings.each (s) ->
settings.each (s) ->
s.originalValue = s.value
result.pushObject(Discourse.SiteSetting.create(s))
result

View File

@ -1,2 +1,2 @@
Discourse.AdminCustomizeRoute = Discourse.Route.extend
model: -> Discourse.SiteCustomization.findAll()
model: -> Discourse.SiteCustomization.findAll()

View File

@ -1,2 +1,2 @@
Discourse.AdminEmailLogsRoute = Discourse.Route.extend
model: -> Discourse.EmailLog.findAll()
model: -> Discourse.EmailLog.findAll()

View File

@ -3,4 +3,4 @@ Discourse.AdminFlagsActiveRoute = Discourse.Route.extend
setupController: (controller, model) ->
c = @controllerFor('adminFlags')
c.set('content', model)
c.set('query', 'active')
c.set('query', 'active')

View File

@ -3,4 +3,4 @@ Discourse.AdminFlagsOldRoute = Discourse.Route.extend
setupController: (controller, model) ->
c = @controllerFor('adminFlags')
c.set('content', model)
c.set('query', 'old')
c.set('query', 'old')

View File

@ -1,2 +1,2 @@
Discourse.AdminUserRoute = Discourse.Route.extend
model: (params) -> Discourse.AdminUser.find(params.username)
model: (params) -> Discourse.AdminUser.find(params.username)

View File

@ -1,2 +1,2 @@
Discourse.AdminUsersListActiveRoute = Discourse.Route.extend
setupController: (c) -> @controllerFor('adminUsersList').show('active')
setupController: (c) -> @controllerFor('adminUsersList').show('active')

View File

@ -1,2 +1,2 @@
Discourse.AdminUsersListNewRoute = Discourse.Route.extend
setupController: (c) -> @controllerFor('adminUsersList').show('new')
setupController: (c) -> @controllerFor('adminUsersList').show('new')

View File

@ -1,2 +1,2 @@
Discourse.AdminUsersListNewRoute = Discourse.Route.extend
setupController: (c) -> @controllerFor('adminUsersList').show('pending')
setupController: (c) -> @controllerFor('adminUsersList').show('pending')

View File

@ -6,7 +6,7 @@ Discourse.AceEditorView = window.Discourse.View.extend
if @editor && !@skipContentChangeEvent
@editor.getSession().setValue(@get('content'))
).observes('content')
render: (buffer) ->
buffer.push("<div class='ace'>")
buffer.push(Handlebars.Utils.escapeExpression(@get('content'))) if @get('content')

View File

@ -10,7 +10,7 @@ Discourse.AdminCustomizeView = window.Discourse.View.extend
headerActive: (->
@get('selected') == 'header'
).property('selected')
stylesheetActive: (->
@get('selected') == 'stylesheet'
).property('selected')
@ -26,7 +26,7 @@ Discourse.AdminCustomizeView = window.Discourse.View.extend
Mousetrap.bindGlobal ['meta+s', 'ctrl+s'], =>
@get('controller').save()
return false
willDestroyElement: ->
Mousetrap.unbindGlobal('meta+s','ctrl+s')

View File

@ -1,2 +1,2 @@
Discourse.AdminDashboardView = window.Discourse.View.extend
templateName: 'admin/templates/dashboard'
templateName: 'admin/templates/dashboard'

View File

@ -1,2 +1,2 @@
Discourse.AdminEmailLogsView = window.Discourse.View.extend
templateName: 'admin/templates/email_logs'
templateName: 'admin/templates/email_logs'

View File

@ -1,2 +1,2 @@
Discourse.AdminSiteSettingsView = window.Discourse.View.extend
templateName: 'admin/templates/site_settings'
templateName: 'admin/templates/site_settings'

View File

@ -1,2 +1,2 @@
Discourse.AdminUserView = window.Discourse.View.extend
templateName: 'admin/templates/user'
templateName: 'admin/templates/user'

View File

@ -1,2 +1,2 @@
Discourse.AdminView = window.Discourse.View.extend
templateName: 'admin/templates/admin'
templateName: 'admin/templates/admin'

View File

@ -23,7 +23,7 @@ window.Discourse = Ember.Application.createWithMixins
title += "#{@get('title')} - " if @get('title')
title += Discourse.SiteSettings.title
$('title').text(title)
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
@ -43,12 +43,12 @@ window.Discourse = Ember.Application.createWithMixins
bus.callbackInterval = Discourse.SiteSettings.anon_polling_interval
bus.enableLongPolling = false
user = @get('currentUser')
if user
bus.callbackInterval = Discourse.SiteSettings.polling_interval
bus.enableLongPolling = true
if user.admin
bus.subscribe "/flagged_counts", (data) ->
user.set('site_flagged_posts_count', data.total)
@ -90,13 +90,13 @@ window.Discourse = Ember.Application.createWithMixins
# 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)
# HTML, say form compiled markdown posts, that need to be routed.
router = Discourse.__container__.lookup('router:main')
router.router.updateURL(path)
router.handleURL(path)
# Scroll to the top if we're not replacing state
# The classes of buttons to show on a post
postButtons: (->
@ -171,7 +171,7 @@ window.Discourse = Ember.Application.createWithMixins
before: (data,owner, args) ->
if owner
window.probes.clear()
after: (data, owner, args) ->
if owner && data.time > 10
f = (name,data) ->
@ -187,7 +187,7 @@ window.Discourse = Ember.Application.createWithMixins
for n,v of window.probes
continue if n == name || v.time < 1
ary.push(k: n, v: v)
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?()
@ -219,9 +219,9 @@ window.Discourse = Ember.Application.createWithMixins
Discourse.MessageBus.start()
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus)
Discourse.insertProbes()
# subscribe to any site customizations that are loaded
# subscribe to any site customizations that are loaded
$('link.custom-css').each ->
split = @href.split("/")
id = split[split.length-1].split(".css")[0]

View File

@ -19,7 +19,7 @@
me = @
div = null
# input is handled differently
# input is handled differently
isInput = @[0].tagName == "INPUT"
inputSelectedItems = []
@ -98,7 +98,7 @@
div.css(left: "-1000px")
me.parent().append(div)
mePos = me.position()
borderTop = parseInt(me.css('border-top-width')) || 0
@ -143,11 +143,11 @@
$(@).keypress (e) ->
if !options.key
return
# keep hunting backwards till you hit a
# keep hunting backwards till you hit a
if e.which == options.key.charCodeAt(0)
caretPosition = Discourse.Utilities.caretPosition(me[0])
@ -165,11 +165,11 @@
return if e.which == 16
if completeStart == null && e.which == 8 && options.key #backspace
c = Discourse.Utilities.caretPosition(me[0])
next = me[0].value[c]
nextIsGood = next == undefined || /\s/.test(next)
c-=1
initial = c
@ -186,7 +186,7 @@
term = me[0].value.substring(c+1, initial)
options.dataSource term, updateAutoComplete
return true
prevIsGood = /[a-zA-Z\.]/.test(prev)
@ -250,6 +250,6 @@
term += "," unless e.which == 8 # backspace
options.dataSource term, updateAutoComplete
return true
)(jQuery)

View File

@ -17,7 +17,7 @@ Discourse.BBCode =
withArgs:
"url": (_, href, title) -> "<a href=\"#{href}\">#{title}</a>"
"email": (_, address, title) -> "<a href=\"mailto:#{address}\">#{title}</a>"
"color": (_, color, content) ->
"color": (_, color, content) ->
return content unless /^(\#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?)|(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)$/.test(color)
"<span style=\"color: #{color}\">#{content}</span>"
@ -28,10 +28,10 @@ Discourse.BBCode =
"i": (_, content) -> "<i>#{content}</i>"
"u": (_, content) -> "<u>#{content}</u>"
"s": (_, content) -> "<s>#{content}</s>"
"spoiler": (_, content) -> "<span style='background-color: #000'>#{content}</span>"
"spoiler": (_, content) -> "<span style='background-color: #000'>#{content}</span>"
withArgs:
"size": (_, size, content) -> "<span style=\"font-size: #{size}px\">#{content}</span>"
"size": (_, size, content) -> "<span style=\"font-size: #{size}px\">#{content}</span>"
# For sane environments that support CSS
default:
@ -58,10 +58,10 @@ Discourse.BBCode =
Object.keys Discourse.BBCode.replacers, (name, rules) ->
parsed = result[name] = []
Object.keys Object.merge(Discourse.BBCode.replacers.base.withoutArgs, rules.withoutArgs), (tag, val) ->
Object.keys Object.merge(Discourse.BBCode.replacers.base.withoutArgs, rules.withoutArgs), (tag, val) ->
parsed.push(regexp: RegExp("\\[#{tag}\\]([\\s\\S]*?)\\[\\/#{tag}\\]", "igm"), fn: val)
Object.keys Object.merge(Discourse.BBCode.replacers.base.withArgs, rules.withArgs), (tag, val) ->
Object.keys Object.merge(Discourse.BBCode.replacers.base.withArgs, rules.withArgs), (tag, val) ->
parsed.push(regexp: RegExp("\\[#{tag}=?(.+?)\\\]([\\s\\S]*?)\\[\\/#{tag}\\]", "igm"), fn: val)
@parsed = result

View File

@ -1,6 +1,6 @@
# caret position in textarea ... very hacky ... sorry
(($) ->
# http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea
getCaret = (el) ->
if el.selectionStart
@ -15,7 +15,7 @@
rc.setEndPoint "EndToStart", re
return rc.text.length
0
clone = null
$.fn.caretPosition = (options) ->
@ -66,15 +66,15 @@
before = pos - 1
after = pos
insertSpaceAfterBefore = false
# if before and after are \n insert a space
# if before and after are \n insert a space
insertSpaceAfterBefore = true if val[before] is "\n" and val[after] is "\n"
guard = (v) ->
buf = v.replace(/</g,"&lt;")
buf = buf.replace(/>/g,"&gt;")
buf = buf.replace(/[ ]/g, "&#x200b;&nbsp;&#x200b;")
buf.replace(/\n/g,"<br />")
makeCursor = (pos, klass, color) ->
l = val.substring(pos, pos + 1)
@ -95,7 +95,7 @@
pos.left = pos.left + letter.width() if letter.hasClass("before")
pPos = p.offset()
#clone.hide().remove()
left: pos.left - pPos.left
top: (pos.top - pPos.top) - clone.scrollTop()
) jQuery

View File

@ -1,4 +1,4 @@
# We use this object to keep track of click counts.
# We use this object to keep track of click counts.
window.Discourse.ClickTrack =
# Pass the event of the click here and we'll do the magic!
@ -28,7 +28,7 @@ window.Discourse.ClickTrack =
userId = $article.data('user-id') unless userId
ownLink = userId and (userId is Discourse.get('currentUser.id'))
# Build a Redirect URL
trackingUrl = "/clicks/track?url=" + encodeURIComponent(href)
trackingUrl += "&post_id=" + encodeURI(postId) if postId and (not $a.data('ignore-post-id'))
@ -44,9 +44,9 @@ window.Discourse.ClickTrack =
# If they right clicked, change the destination href
if e.which is 3
destination = if Discourse.SiteSettings.track_external_right_clicks then trackingUrl else href
$a.attr('href', destination)
$a.attr('href', destination)
return true
# if they want to open in a new tab, do an AJAX request
if (e.metaKey || e.ctrlKey || e.which is 2)
$.get "/clicks/track", url: href, post_id: postId, topic_id: topicId, redirect: false

View File

@ -42,12 +42,12 @@
mousePosition = (e) ->
x: e.clientX + document.documentElement.scrollLeft
y: e.clientY + document.documentElement.scrollTop
$.fn.DivResizer = (opts) ->
@each ->
div = $(this)
return if (div.hasClass("processed"))
div.addClass("processed")
staticOffset = null

View File

@ -44,10 +44,10 @@ class Discourse.Eyeline
return true unless markSeen
# If you hit the bottom we mark all the elements as seen. Otherwise, just the first one
# If you hit the bottom we mark all the elements as seen. Otherwise, just the first one
unless atBottom
@trigger('saw', detail: $elem)
@trigger('sawTop', detail: $elem) if i == 0
@trigger('saw', detail: $elem)
@trigger('sawTop', detail: $elem) if i == 0
return false
@trigger('sawTop', detail: $elem) if i == 0
@ -56,9 +56,9 @@ class Discourse.Eyeline
# Call this when we know aren't loading any more elements. Mark the rest
# as seen
flushRest: ->
$(@selector).each (i, elem) =>
$(@selector).each (i, elem) =>
$elem = $(elem)
@trigger('saw', detail: $elem)
@trigger('saw', detail: $elem)
RSVP.EventTarget.mixin(Discourse.Eyeline.prototype)
RSVP.EventTarget.mixin(Discourse.Eyeline.prototype)

View File

@ -4,7 +4,7 @@
window.Discourse.KeyValueStore = (->
initialized = false
context = ""
init: (ctx,messageBus) ->
initialized = true
context = ctx
@ -17,7 +17,7 @@ window.Discourse.KeyValueStore = (->
localStorage.removeItem(k) if k.substring(0, context.length) == context
i--
return true
remove: (key)->
localStorage.removeItem(context + key)

View File

@ -45,11 +45,11 @@ window.Discourse.MessageBus = ( ->
if callbacks.length == 0
setTimeout poll, 500
return
data = {}
callbacks.each (c)->
data[c.channel] = if c.last_id == undefined then -1 else c.last_id
gotData = false
@longPoll = $.ajax "/message-bus/#{clientId}/poll?#{if isHidden() || !@enableLongPolling then "dlp=t" else ""}",
@ -98,7 +98,7 @@ window.Discourse.MessageBus = ( ->
subscribe: (channel,func,lastId)->
callbacks.push {channel:channel, func:func, last_id: lastId}
@longPoll.abort() if @longPoll
# Unsubscribe from a channel
unsubscribe: (channel) ->
# TODO proper globbing

View File

@ -9,7 +9,7 @@ window.Discourse.PagedownEditor = Ember.ContainerView.extend
@pushObject Em.View.create(elementId: 'wmd-button-bar')
@pushObject Em.TextArea.create(valueBinding: 'parentView.value', elementId: 'wmd-input')
@pushObject Em.View.createWithMixins Discourse.Presence,
elementId: 'wmd-preview',
elementId: 'wmd-preview',
classNameBindings: [':preview', 'hidden']
hidden: (->

View File

@ -76,7 +76,7 @@ window.Discourse.ScreenTrack = Ember.Object.extend
if (highestSeenByTopic[topicId] || 0) < @highestSeen
highestSeenByTopic[topicId] = @highestSeen
unless Object.isEmpty(newTimings)
$.ajax '/topics/timings'
data:
@ -93,7 +93,7 @@ window.Discourse.ScreenTrack = Ember.Object.extend
@lastFlush = 0
tick: ->
# If the user hasn't scrolled the browser in a long time, stop tracking time read
sinceScrolled = new Date().getTime() - @lastScrolled
if sinceScrolled > @PAUSE_UNLESS_SCROLLED
@ -116,7 +116,7 @@ window.Discourse.ScreenTrack = Ember.Object.extend
Object.keys @timings, (id) =>
$element = $(id)
if ($element.length == 1)
elemTop = $element.offset().top
elemBottom = elemTop + $element.height()

View File

@ -1,4 +1,4 @@
# Helper object for syntax highlighting. Uses highlight.js which is loaded
# Helper object for syntax highlighting. Uses highlight.js which is loaded
# on demand.
window.Discourse.SyntaxHighlighting =

View File

@ -1,4 +1,4 @@
# CSS transitions are a PITA, often we need to queue some js after a transition, this helper ensures
# CSS transitions are a PITA, often we need to queue some js after a transition, this helper ensures
# it happens after the transition
#

View File

@ -24,8 +24,8 @@ window.Discourse.UserSearch =
limit = options.limit || 5
throw "missing callback" unless callback
#TODO site setting for allowed regex in username ?
#TODO site setting for allowed regex in username ?
if term.match(/[^a-zA-Z0-9\_\.]/)
callback([])
return true

View File

@ -25,9 +25,9 @@ Discourse.Utilities =
return "" unless username
size = Discourse.Utilities.translateSize(size)
rawSize = (size * (window.devicePixelRatio || 1)).toFixed()
return template.replace(/\{size\}/g, rawSize) if template
"/users/#{username.toLowerCase()}/avatar/#{rawSize}?__ws=#{encodeURIComponent(Discourse.BaseUrl || "")}"
avatarImg: (options)->
@ -63,7 +63,7 @@ Discourse.Utilities =
caretPosition: (el) ->
return el.selectionStart if el.selectionStart
if document.selection
el.focus()
r = document.selection.createRange()
@ -121,7 +121,7 @@ Discourse.Utilities =
result = text.replace /^`{3}(?:(.*$)\n)?([\s\S]*?)^`{3}/gm, (wholeMatch,m1,m2) ->
escaped = Handlebars.Utils.escapeExpression(m2)
"<pre><code class='#{m1 || 'lang-auto'}'>#{escaped}</code></pre>"
converter.hooks.chain "postConversion", (text) ->
return "" unless text
# don't to mention voodoo in pres

View File

@ -3,4 +3,4 @@ window.Discourse.ApplicationController = Ember.Controller.extend
needs: ['modal']
showLogin: ->
@get('controllers.modal')?.show(Discourse.LoginView.create())
@get('controllers.modal')?.show(Discourse.LoginView.create())

View File

@ -24,18 +24,18 @@ window.Discourse.ComposerController = Ember.Controller.extend Discourse.Presence
, (error) =>
composer.set('disableDrafts', false)
bootbox.alert error
saveDraft: ->
model = @get('content')
model.saveDraft() if model
# Open the reply view
#
#
# opts:
# action - The action we're performing: edit, reply or createTopic
# action - The action we're performing: edit, reply or createTopic
# post - The post we're replying to, if present
# topic - The topic we're replying to, if present
# quote - If we're opening a reply from a quote, the quote we're making
# quote - If we're opening a reply from a quote, the quote we're making
#
open: (opts={}) ->
opts.promise = promise = opts.promise || new RSVP.Promise
@ -51,7 +51,7 @@ window.Discourse.ComposerController = Ember.Controller.extend Discourse.Presence
controller: @
view.appendTo($('#main'))
@set('view', view)
# the next runloop is too soon, need to get the control rendered and then
# the next runloop is too soon, need to get the control rendered and then
# we need to change stuff, otherwise css animations don't kick in
Em.run.next =>
Em.run.next =>
@ -87,7 +87,7 @@ window.Discourse.ComposerController = Ember.Controller.extend Discourse.Presence
if opts.draft
composer = Discourse.Composer.loadDraft(opts.draftKey, opts.draftSequence, opts.draft)
composer?.set('topic', opts.topic)
composer = composer || Discourse.Composer.open(opts)
@set('content', composer)
@ -119,7 +119,7 @@ window.Discourse.ComposerController = Ember.Controller.extend Discourse.Presence
else
fail() if typeof fail == "function"
else
# it is possible there is some sort of crazy draft with no body ... just give up on it
# it is possible there is some sort of crazy draft with no body ... just give up on it
@destroyDraft()
@close()
success() if typeof success == "function"
@ -133,7 +133,7 @@ window.Discourse.ComposerController = Ember.Controller.extend Discourse.Presence
shrink: ->
if @get('content.reply') == @get('content.originalText') then @close() else @collapse()
collapse: ->
@saveDraft()
@set('content.composeState', Discourse.Composer.DRAFT)
@ -166,7 +166,7 @@ window.Discourse.ComposerController = Ember.Controller.extend Discourse.Presence
# ESC key hit
hitEsc: ->
@shrink() if @get('content.composeState') == @OPEN
showOptions: ->
@get('controllers.modal')?.show(Discourse.ArchetypeOptionsModalView.create(archetype: @get('content.archetype'), metaData: @get('content.metaData')))

View File

@ -1 +1 @@
Discourse.Controller = Ember.Controller.extend(Discourse.Presence)
Discourse.Controller = Ember.Controller.extend(Discourse.Presence)

View File

@ -4,4 +4,4 @@ Discourse.HeaderController = Ember.Controller.extend Discourse.Presence,
toggleStar: ->
@get('topic')?.toggleStar()
false
false

View File

@ -14,7 +14,7 @@ Discourse.ListCategoriesController = Ember.ObjectController.extend Discourse.Pre
editCategory: (category) ->
@get('controllers.modal').show(Discourse.EditCategoryView.create(category: category))
false
canEdit: (->
u = Discourse.get('currentUser')
u && u.admin

View File

@ -9,7 +9,7 @@ Discourse.ListTopicsController = Ember.ObjectController.extend
if previousChannel = @get('previousChannel')
Discourse.MessageBus.unsubscribe "/#{previousChannel}"
@set('previousChannel', null)
filterMode = @get('controllers.list.filterMode')
return unless filterMode
@ -19,7 +19,7 @@ Discourse.ListTopicsController = Ember.ObjectController.extend
@set('previousChannel', channel)
).observes('controllers.list.filterMode')
draftLoaded: (->
draft = @get('content.draft')
if(draft)

View File

@ -36,7 +36,7 @@ Discourse.PreferencesController = Ember.ObjectController.extend Discourse.Presen
@get('content').save (result) =>
@set('saving', false)
if result
@set('content.bio_cooked', Discourse.Utilities.cook(@get('content.bio_raw')))
@set('content.bio_cooked', Discourse.Utilities.cook(@get('content.bio_raw')))
@set('saved', true)
else
alert 'failed'
@ -51,4 +51,4 @@ Discourse.PreferencesController = Ember.ObjectController.extend Discourse.Presen
@set('passwordProgress','(generating email)')
@get('content').changePassword (message)=>
@set('changePasswordProgress', false)
@set('passwordProgress', "(#{message})")
@set('passwordProgress', "(#{message})")

View File

@ -29,7 +29,7 @@ Discourse.PreferencesEmailController = Ember.ObjectController.extend Discourse.P
@set('saving', true)
@get('content').changeEmail(@get('newEmail')).then =>
@set('success', true)
, =>
, =>
# Error
@set('error', true)
@set('saving', false)

View File

@ -34,7 +34,7 @@ Discourse.PreferencesUsernameController = Ember.ObjectController.extend Discours
@set('saving', true)
@get('content').changeUsername(@get('newUsername')).then =>
window.location = "/users/#{@get('newUsername').toLowerCase()}/preferences"
, =>
, =>
# Error
@set('error', true)
@set('saving', false)

View File

@ -20,7 +20,7 @@ Discourse.QuoteButtonController = Discourse.Controller.extend
selectText: (e) ->
return unless Discourse.get('currentUser')
return unless @get('controllers.topic.content.can_create_post')
selectedText = Discourse.Utilities.selectedText()
return if @get('buffer') == selectedText
return if @get('lastSelected') == selectedText
@ -51,20 +51,20 @@ Discourse.QuoteButtonController = Discourse.Controller.extend
post: post
action: Discourse.Composer.REPLY
draftKey: @get('post.topic.draft_key')
# If the composer is associated with a different post, we don't change it.
if composerPost = composerController.get('content.post')
composerOpts.post = composerPost if (composerPost.get('id') != @get('post.id'))
buffer = @get('buffer')
quotedText = Discourse.BBCode.buildQuoteBBCode(post, buffer)
if composerController.wouldLoseChanges()
composerController.appendText(quotedText)
else
composerController.open(composerOpts).then =>
composerController.appendText(quotedText)
@set('buffer', '')
false

View File

@ -8,7 +8,7 @@ Discourse.ShareController = Ember.Controller.extend
@set('link', url)
false
# Close the share controller
# Close the share controller
close: ->
@set('link', '')
false

View File

@ -9,13 +9,13 @@ Discourse.StaticController = Ember.Controller.extend
$preloaded = $("noscript[data-path=\"#{path}\"]")
if $preloaded.length
text = $preloaded.text()# + ""
text = text.replace(/\<header[\s\S]*\<\/header\>/, '')
text = text.replace(/\<header[\s\S]*\<\/header\>/, '')
@set('content', text)
else
else
jQuery.ajax
url: "#{path}.json"
success: (result) =>
@set('content', result)
Discourse.StaticController.reopenClass(pages: ['faq', 'tos', 'privacy'])
Discourse.StaticController.reopenClass(pages: ['faq', 'tos', 'privacy'])

View File

@ -3,4 +3,4 @@ Discourse.TopicAdminMenuController = Ember.ObjectController.extend
visible: false
show: -> @set('visible', true)
hide: -> @set('visible', false)
hide: -> @set('visible', false)

View File

@ -49,7 +49,7 @@ Discourse.TopicController = Ember.ObjectController.extend Discourse.Presence,
unless p.get('can_delete')
canDelete = false
return false
canDelete
).property('selectedPosts')
@ -58,7 +58,7 @@ Discourse.TopicController = Ember.ObjectController.extend Discourse.Presence,
unless @get('multiSelect')
if posts = @get('content.posts')
posts.forEach (p) -> p.set('selected', false)
).observes('multiSelect')
hideProgress: (->
@ -95,7 +95,7 @@ Discourse.TopicController = Ember.ObjectController.extend Discourse.Presence,
replyAsNewTopic: (post) ->
composerController = @get('controllers.composer')
#TODO shut down topic draft cleanly if it exists ...
#TODO shut down topic draft cleanly if it exists ...
promise = composerController.open
action: Discourse.Composer.CREATE_TOPIC
draftKey: Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY
@ -103,7 +103,7 @@ Discourse.TopicController = Ember.ObjectController.extend Discourse.Presence,
postUrl = "#{location.protocol}//#{location.host}#{post.get('url')}"
postLink = "[#{@get('title')}](#{postUrl})"
promise.then ->
Discourse.Post.loadQuote(post.get('id')).then (q) ->
Discourse.Post.loadQuote(post.get('id')).then (q) ->
composerController.appendText("#{Em.String.i18n("post.continue_discussion", postLink: postLink)}\n\n#{q}")
# Topic related
@ -145,14 +145,14 @@ Discourse.TopicController = Ember.ObjectController.extend Discourse.Presence,
return unless topic
posts = topic.get('posts')
return unless posts
posts.clear()
posts.clear()
@set('content.loaded', false)
Discourse.Topic.find(@get('content.id'), @get('postFilters')).then (result) =>
first = result.posts.first()
@set('currentPost', first.post_number) if first
$('#topic-progress .solid').data('progress', false)
result.posts.each (p) =>
result.posts.each (p) =>
posts.pushObject(Discourse.Post.create(p, topic))
@set('content.loaded', true)
@ -163,7 +163,7 @@ Discourse.TopicController = Ember.ObjectController.extend Discourse.Presence,
@get('content').delete =>
@set('message', "The topic has been deleted")
@set('loaded', false)
@set('loaded', false)
toggleVisibility: ->
@get('content').toggleStatus('visible')
@ -226,7 +226,7 @@ Discourse.TopicController = Ember.ObjectController.extend Discourse.Presence,
quoteController = @get('controllers.quoteButton')
quotedText = Discourse.BBCode.buildQuoteBBCode(quoteController.get('post'), quoteController.get('buffer'))
quoteController.set('buffer', '')
if (composerController.get('content.topic.id') == post.get('topic.id') and composerController.get('content.action') == Discourse.Composer.REPLY)
composerController.set('content.post', post)
composerController.set('content.composeState', Discourse.Composer.OPEN)

View File

@ -2,4 +2,4 @@ Discourse.UserInvitedController = Ember.ObjectController.extend
rescind: (invite) ->
invite.rescind()
false
false

View File

@ -2,7 +2,7 @@ Discourse.UserPrivateMessagesController = Ember.ObjectController.extend
editPreferences: ->
Discourse.routeTo("/users/#{@get('content.username_lower')}/preferences")
composePrivateMessage: ->
composerController = Discourse.get('router.composerController')
composerController.open

View File

@ -1,16 +1,16 @@
Handlebars.registerHelper 'breakUp', (property, options) ->
prop = Ember.Handlebars.get(this, property, options)
return "" unless prop
tokens = prop.match(RegExp(".{1,14}",'g'))
return prop if tokens.length == 1
result = ""
result = ""
tokens.each (token, index) ->
result += token
if token.indexOf(' ') == -1 and (index < tokens.length - 1)
result += "- "
result += "- "
result
@ -28,9 +28,9 @@ Handlebars.registerHelper 'categoryLink', (property, options) ->
Handlebars.registerHelper 'titledLinkTo', (name, object) ->
options = [].slice.call(arguments, -1)[0]
if options.hash.titleKey
options.hash.title = Em.String.i18n(options.hash.titleKey)
if options.hash.titleKey
options.hash.title = Em.String.i18n(options.hash.titleKey)
if arguments.length is 3
Ember.Handlebars.helpers.linkTo.call(this, name, object, options)
@ -43,7 +43,7 @@ Handlebars.registerHelper 'shortenUrl', (property, options) ->
# Remove trailing slash if it's a top level URL
url = url.replace(/\/$/, '') if url.match(/\//g).length == 3
url = url.replace(/^https?:\/\//, '')
url = url.replace(/^www\./, '')
url.truncate(80)
@ -68,7 +68,7 @@ Handlebars.registerHelper 'avatar', (user, options) ->
title: Em.get(user, 'title') || Em.get(user, 'description')
avatarTemplate: Ember.get(user, 'avatar_template') || options.hash.avatarTemplate
)
Handlebars.registerHelper 'unboundDate', (property, options) ->
dt = new Date(Ember.Handlebars.get(this, property, options))
month = Date.SugarMethods.getLocale.method().months[12 + dt.getMonth()]
@ -104,7 +104,7 @@ Handlebars.registerHelper 'date', (property, options) ->
val = Ember.Handlebars.get(this, property, options)
return new Handlebars.SafeString("&mdash;") unless val
dt = new Date(val)
fullReadable = dt.format("{d} {Mon}, {yyyy} {hh}:{mm}")
@ -122,7 +122,7 @@ Handlebars.registerHelper 'date', (property, options) ->
return "" unless humanized
displayDate = humanized
displayDate = displayDate.replace(' ago', '') unless leaveAgo
new Handlebars.SafeString("<span class='date' title='#{fullReadable}'>#{displayDate}</span>")

View File

@ -9,7 +9,7 @@ window.Discourse.Presence = Em.Mixin.create
when "string"
return prop.trim().isBlank()
when "object"
return Object.isEmpty(prop)
return Object.isEmpty(prop)
false
present: (name) -> not @blank(name)
present: (name) -> not @blank(name)

View File

@ -29,7 +29,7 @@ window.Discourse.ActionSummary = Em.Object.extend Discourse.Presence,
@set('can_undo', true)
#TODO: mark all other flag types as acted
# Add ourselves to the users who liked it if present
@users.pushObject(Discourse.get('currentUser')) if @present('users')
@ -45,7 +45,7 @@ window.Discourse.ActionSummary = Em.Object.extend Discourse.Presence,
@removeAction()
errors = jQuery.parseJSON(error.responseText).errors
bootbox.alert(errors[0])
# Undo this action
undo: ->
@ -57,7 +57,7 @@ window.Discourse.ActionSummary = Em.Object.extend Discourse.Presence,
type: 'DELETE'
data:
post_action_type_id: @get('id')
clearFlags: ->
$.ajax
url: "/post_actions/clear_flags"

View File

@ -18,14 +18,14 @@ window.Discourse.Composer = Discourse.Model.extend
val = (Discourse.KeyValueStore.get('composer.showPreview') or 'true')
@set('showPreview', val is 'true')
@set 'archetypeId', Discourse.get('site.default_archetype')
archetypesBinding: 'Discourse.site.archetypes'
creatingTopic: (-> @get('action') == CREATE_TOPIC ).property('action')
creatingPrivateMessage: (-> @get('action') == PRIVATE_MESSAGE ).property('action')
editingPost: (-> @get('action') == EDIT).property('action')
viewOpen: (-> @get('composeState') == OPEN ).property('composeState')
archetype: (->
@get('archetypes').findProperty('id', @get('archetypeId'))
).property('archetypeId')
@ -44,7 +44,7 @@ window.Discourse.Composer = Discourse.Model.extend
togglePreview: ->
@toggleProperty('showPreview')
Discourse.KeyValueStore.set(key: 'showPreview', value: @get('showPreview'))
# Import a quote from the post
importQuote: ->
post = @get('post')
@ -95,7 +95,7 @@ window.Discourse.Composer = Discourse.Model.extend
).property('showPreview')
hidePreview: (-> not @get('showPreview') ).property('showPreview')
# Whether to disable the post button
cantSubmitPost: (->
@ -113,7 +113,7 @@ window.Discourse.Composer = Discourse.Model.extend
false
).property('reply', 'title', 'creatingTopic', 'loading')
# The text for the save button
saveText: (->
switch @get('action')
@ -129,20 +129,20 @@ window.Discourse.Composer = Discourse.Model.extend
return Em.empty(Em.keys(@get('metaData')))
).property('metaData')
wouldLoseChanges: ()->
@get('reply') != @get('originalText') # TODO title check as well
# Open a composer
#
#
# opts:
# action - The action we're performing: edit, reply or createTopic
# action - The action we're performing: edit, reply or createTopic
# post - The post we're replying to, if present
# topic - The topic we're replying to, if present
# quote - If we're opening a reply from a quote, the quote we're making
# quote - If we're opening a reply from a quote, the quote we're making
#
open: (opts={}) ->
@set('loading', false)
topicId = opts.topic.get('id') if opts.topic
@ -151,7 +151,7 @@ window.Discourse.Composer = Discourse.Model.extend
opts.tested = true
@cancel(=> @open(opts))
return
@set 'draftKey', opts.draftKey
@set 'draftSequence', opts.draftSequence
throw 'draft key is required' unless opts.draftKey
@ -177,7 +177,7 @@ window.Discourse.Composer = Discourse.Model.extend
Discourse.Post.load opts.postId, (result) =>
@set('post', result)
@set('loading', false)
# If we are editing a post, load it.
if opts.action == EDIT and opts.post
@set 'title', @get('topic.title')
@ -186,7 +186,7 @@ window.Discourse.Composer = Discourse.Model.extend
@set 'reply', result.get('raw')
@set('originalText', @get('reply'))
@set('loading', false)
if opts.title
@set('title', opts.title)
if opts.draft
@ -196,7 +196,7 @@ window.Discourse.Composer = Discourse.Model.extend
false
save: (opts)->
if @get('editingPost')
@editPost(opts)
@ -230,7 +230,7 @@ window.Discourse.Composer = Discourse.Model.extend
postNumber = post.get('post_number')
posts.each (p,i)->
idx = i if p.get('post_number') == postNumber
if idx > -1
savedPost.set('topic', @get('topic'))
posts.replace(idx, 1, [savedPost])
@ -244,7 +244,7 @@ window.Discourse.Composer = Discourse.Model.extend
@set('composeState', OPEN)
promise
# Create a new Post
createPost: (opts)->
@ -274,9 +274,9 @@ window.Discourse.Composer = Discourse.Model.extend
addedToStream = false
# If we're in a topic, we can append the post instantly.
# If we're in a topic, we can append the post instantly.
if topic
# Increase the reply count
# Increase the reply count
if post
post.set('reply_count', (post.get('reply_count') || 0) + 1)
@ -299,17 +299,17 @@ window.Discourse.Composer = Discourse.Model.extend
# If we're near the end of the topic, load new posts
lastPost = topic.posts.last()
if lastPost
diff = topic.get('highest_post_number') - lastPost.get('post_number')
# If the new post is within a threshold of the end of the topic,
# If the new post is within a threshold of the end of the topic,
# add it and scroll there instead of adding the link.
if diff < 5
createdPost.set('scrollToAfterInsert', createdPost.get('post_number'))
topic.pushPosts([createdPost])
addedToStream = true
# Save callback
createdPost.save (result) =>
addedPost = false
@ -323,7 +323,7 @@ window.Discourse.Composer = Discourse.Model.extend
# We created a new topic, let's show it.
@set('composeState', CLOSED)
saving = false
@set('reply', '')
@set('createdPost', createdPost)
@ -354,7 +354,7 @@ window.Discourse.Composer = Discourse.Model.extend
archetypeId: @get('archetypeId')
metaData: @get('metaData')
usernames: @get('targetUsernames')
@set('draftStatus', Em.String.i18n('composer.saving_draft_tip'))
Discourse.Draft.save(@get('draftKey'), @get('draftSequence'), data)
.then(
@ -417,6 +417,6 @@ Discourse.Composer.reopenClass
EDIT: EDIT
# Draft key
REPLY_AS_NEW_TOPIC_KEY: REPLY_AS_NEW_TOPIC_KEY
REPLY_AS_NEW_TOPIC_KEY: REPLY_AS_NEW_TOPIC_KEY

View File

@ -18,11 +18,11 @@ Discourse.Draft.reopenClass
success: (data) =>
promise.resolve(data)
promise
getLocal: (key, current) ->
return current
# disabling for now to see if it helps with siracusa issue.
# disabling for now to see if it helps with siracusa issue.
local = Discourse.KeyValueStore.get("draft_#{key}")
if !current || (local && local.length > current.length)
@ -46,6 +46,6 @@ Discourse.Draft.reopenClass
# Discourse.KeyValueStore.set(key: "draft_#{key}", value: data)
promise.reject()
promise

View File

@ -1,10 +1,10 @@
window.Discourse.InviteList = Discourse.Model.extend Discourse.Presence,
empty: (->
empty: (->
return @blank('pending') and @blank('redeemed')
).property('pending.@each', 'redeemed.@each')
window.Discourse.InviteList.reopenClass
window.Discourse.InviteList.reopenClass
findInvitedBy: (user) ->
promise = new RSVP.Promise()
@ -16,4 +16,4 @@ window.Discourse.InviteList.reopenClass
invitedList.redeemed = (invitedList.redeemed.map (i) -> Discourse.Invite.create(i)) if invitedList.redeemed
invitedList.user = user
promise.resolve(Discourse.InviteList.create(invitedList))
promise
promise

View File

@ -5,7 +5,7 @@ Discourse.Mention = (->
cache = (name, valid) ->
localCache[name] = valid
return
lookupCache = (name) ->
localCache[name]
@ -19,7 +19,7 @@ Discourse.Mention = (->
cache(name,r.valid)
callback(r.valid)
return true
load = (e) ->
$elem = $(e)
return if $elem.data('mention-tested')
@ -38,4 +38,4 @@ Discourse.Mention = (->
lookup: lookup
lookupCache: lookupCache
)()

View File

@ -20,9 +20,9 @@ window.Discourse.Model = Ember.Object.extend
col = @get(k)
v.each (obj) -> col.pushObject(builder.create(obj))
else
@set(k, v)
@set(k, v)
window.Discourse.Model.reopenClass
# Given an array of values, return them in a hash
@ -33,4 +33,4 @@ window.Discourse.Model.reopenClass
collection.each (c) ->
obj = klass.create(c)
retval[c.id] = obj
retval
retval

View File

@ -27,11 +27,11 @@ Discourse.NavItem.reopenClass
countSummary = opts["countSummary"]
loggedOn = opts["loggedOn"]
hasCategories = opts["hasCategories"]
split = text.split(",")
name = split[0]
testName = name.split("/")[0] # to handle category ...
testName = name.split("/")[0] # to handle category ...
return null if !loggedOn && !validAnon.contains(testName)
return null if !hasCategories && testName == "categories"

View File

@ -20,7 +20,7 @@ window.Discourse.Notification = Discourse.Model.extend Discourse.Presence,
window.Discourse.Notification.reopenClass
create: (obj) ->
result = @_super(obj)
result.set('data', Em.Object.create(obj.data)) if obj.data

View File

@ -1,5 +1,5 @@
Discourse.Onebox = (->
# for now it only stores in a var, in future we can change it so it uses localStorage,
# for now it only stores in a var, in future we can change it so it uses localStorage,
# trouble with localStorage is that expire semantics need some thinking
#cacheKey = "__onebox__"
@ -9,9 +9,9 @@ Discourse.Onebox = (->
localCache[url] = contents
#if localStorage && localStorage.setItem
# localStorage.setItme
# localStorage.setItme
null
lookupCache = (url) ->
localCache[url]
@ -25,7 +25,7 @@ Discourse.Onebox = (->
cache(url,html)
callback(html)
return true
load = (e, refresh=false) ->
url = e.href
@ -45,4 +45,4 @@ Discourse.Onebox = (->
lookup: lookup
lookupCache: lookupCache
)()

View File

@ -52,14 +52,14 @@ Discourse.Topic = Discourse.Model.extend Discourse.Presence,
).observes('posts.@each','posts')
# The amount of new posts to display. It might be different than what the server
# tells us if we are still asynchronously flushing our "recently read" data.
# tells us if we are still asynchronously flushing our "recently read" data.
# So take what the browser has seen into consideration.
displayNewPosts: (->
if highestSeen = Discourse.get('highestSeenByTopic')[@get('id')]
delta = highestSeen - @get('last_read_post_number')
if delta > 0
result = (@get('new_posts') - delta)
result = (@get('new_posts') - delta)
result = 0 if result < 0
return result
@ -78,9 +78,9 @@ Discourse.Topic = Discourse.Model.extend Discourse.Presence,
ageCold: (->
return unless lastPost = @get('last_posted_at')
return unless createdAt = @get('created_at')
daysSinceEpoch = (dt) ->
# 1000 * 60 * 60 * 24 = days since epoch
# 1000 * 60 * 60 * 24 = days since epoch
dt.getTime() / 86400000
# Show heat on age
@ -169,12 +169,12 @@ Discourse.Topic = Discourse.Model.extend Discourse.Presence,
bestOf: opts.bestOf
trackVisit: opts.trackVisit
.then (result) =>
# If loading the topic succeeded...
# Update the slug if different
@set('slug', result.slug) if result.slug
# If we want to scroll to a post that doesn't exist, just pop them to the closest
# If we want to scroll to a post that doesn't exist, just pop them to the closest
# one instead. This is likely happening due to a deleted post.
opts.nearPost = parseInt(opts.nearPost)
closestPostNumber = 0
@ -189,7 +189,7 @@ Discourse.Topic = Discourse.Model.extend Discourse.Presence,
@get('participants').clear() if @get('participants')
@set('suggested_topics', Em.A()) if result.suggested_topics
@mergeAttributes result, suggested_topics: Discourse.Topic
@set('posts', Em.A())
@ -237,7 +237,7 @@ Discourse.Topic = Discourse.Model.extend Discourse.Presence,
url: "/t/#{@get('id')}/notifications"
type: 'POST'
data: {notification_level: v}
# use to add post to topics protecting from dupes
pushPosts: (newPosts)->
map = {}
@ -257,13 +257,13 @@ window.Discourse.Topic.reopenClass
MUTE: 0
# Load a topic, but accepts a set of filters
#
#
# options:
# onLoad - the callback after the topic is loaded
find: (topicId, opts) ->
url = "/t/#{topicId}"
url += "/#{opts.nearPost}" if opts.nearPost
data = {}
data.posts_after = opts.postsAfter if opts.postsAfter
data.posts_before = opts.postsBefore if opts.postsBefore
@ -276,7 +276,7 @@ window.Discourse.Topic.reopenClass
# Add the best of filter if we have it
data.best_of = true if opts.bestOf == true
# Check the preload store. If not, load it via JSON
promise = new RSVP.Promise()
PreloadStore.get("topic_#{topicId}", -> jQuery.getJSON url + ".json", data).then (result) ->
@ -286,7 +286,7 @@ window.Discourse.Topic.reopenClass
, (result) -> promise.reject(result)
promise
# Create a topic from posts
movePosts: (topicId, title, postIds) ->
$.ajax "/t/#{topicId}/move-posts",

View File

@ -2,7 +2,7 @@ window.Discourse.TopicList = Discourse.Model.extend
emptyListTip: (->
return null unless @get('loaded')
t = @get('topics')
return null if t && t.length > 0
@ -32,7 +32,7 @@ window.Discourse.TopicList = Discourse.Model.extend
insert: (json) ->
newTopic = Discourse.TopicList.decodeTopic(json)
# New Topics are always unseen
newTopic.set('unseen', true)
@ -75,7 +75,7 @@ window.Discourse.TopicList.reopenClass
url = "/#{filter}.json"
if menuItem.filters && menuItem.filters.length > 0
url += "?exclude_category=" + menuItem.filters[0].substring(1)
if list = Discourse.get('transient.topicsList')
if (list.get('filter') is filter) and window.location.pathname.indexOf('more') > 0
promise = new RSVP.Promise()

View File

@ -26,11 +26,11 @@ window.Discourse.User = Discourse.Model.extend Discourse.Presence,
username_lower:(->
@get('username').toLowerCase()
).property('username')
trustLevel: (->
Discourse.get('site.trust_levels').findProperty('id', @get('trust_level'))
).property('trust_level')
changeUsername: (newUsername) ->
$.ajax
url: "/users/#{@get('username_lower')}/preferences/username"
@ -41,7 +41,7 @@ window.Discourse.User = Discourse.Model.extend Discourse.Presence,
$.ajax
url: "/users/#{@get('username_lower')}/preferences/email"
type: 'PUT'
data: {email: email}
data: {email: email}
copy: (deep) ->
Discourse.User.create(@getProperties(Ember.keys(@)))
@ -164,7 +164,7 @@ window.Discourse.User.reopenClass
if s.action_type == k
g[k] = s
s.count = c
g[s.action_type] = s unless found
stats.map((s)->

View File

@ -2,4 +2,4 @@ window.Discourse.ApplicationRoute = Discourse.Route.extend
setupController: (controller) ->
Discourse.set('site', Discourse.Site.create(PreloadStore.getStatic('site')))
currentUser = PreloadStore.getStatic('currentUser')
Discourse.set('currentUser', Discourse.User.create(currentUser)) if currentUser
Discourse.set('currentUser', Discourse.User.create(currentUser)) if currentUser

View File

@ -6,7 +6,7 @@ Discourse.buildRoutes ->
@route 'bestOf', path: '/best_of'
# Generate static page routes
router = @
router = @
Discourse.StaticController.pages.forEach (p) -> router.route(p, path: "/#{p}")
@route 'faq', path: '/faq'
@ -24,10 +24,10 @@ Discourse.buildRoutes ->
router.route 'categories', path: '/categories'
router.route 'category', path: '/category/:slug/more'
router.route 'category', path: '/category/:slug'
@resource 'user', path: '/users/:username', ->
@route 'activity', path: '/'
@resource 'preferences', path: '/preferences', ->
@route 'username', path: '/username'
@route 'email', path: '/email'

View File

@ -18,8 +18,8 @@ window.Discourse.Route = Em.Route.extend
# Hide any searches
if search = router.get('searchController')
search.close()
# get rid of "save as draft stuff"
# get rid of "save as draft stuff"
composerController = Discourse.get('router.composerController')
composerController.closeIfCollapsed() if composerController

View File

@ -19,5 +19,5 @@ window.Discourse.FilteredListRoute = Discourse.Route.extend
Discourse.ListController.filters.each (filter) ->
window.Discourse["List#{filter.capitalize()}Route"] = Discourse.FilteredListRoute.extend(filter: filter)

View File

@ -10,4 +10,4 @@ window.Discourse.ListCategoriesRoute = Discourse.Route.extend
@render 'listCategories', into: 'list', outlet: 'listView', controller: 'listCategories'
listController.set('canCreateCategory', categoryList.get('can_create_category'))
listController.set('category', null)
@controllerFor('listCategories').set('content', categoryList)
@controllerFor('listCategories').set('content', categoryList)

View File

@ -7,4 +7,4 @@ window.Discourse.ListCategoryRoute = Discourse.FilteredListRoute.extend
listController.load("category/#{model.slug}").then (topicList) =>
listController.set('canCreateTopic', topicList.get('can_create_topic'))
listController.set('category', Discourse.Category.create(name: model.slug))
@controllerFor('listTopics').set('content', topicList)
@controllerFor('listTopics').set('content', topicList)

View File

@ -2,4 +2,4 @@ window.Discourse.PreferencesEmailRoute = Discourse.Route.extend
renderTemplate: ->
@render into: 'user', outlet: 'userOutlet'
setupController: (controller) ->
controller.set('content', @controllerFor('user').get('content'))
controller.set('content', @controllerFor('user').get('content'))

View File

@ -3,4 +3,4 @@ window.Discourse.PreferencesRoute = Discourse.Route.extend
@render 'preferences', into: 'user', outlet: 'userOutlet', controller: 'preferences'
setupController: (controller) ->
controller.set('content', @controllerFor('user').get('content'))
controller.set('content', @controllerFor('user').get('content'))

View File

@ -4,4 +4,4 @@ window.Discourse.PreferencesUsernameRoute = Discourse.Route.extend
setupController: (controller) ->
user = @controllerFor('user').get('content')
controller.set('content', user)
controller.set('newUsername', user.get('username'))
controller.set('newUsername', user.get('username'))

View File

@ -1,4 +1,4 @@
Discourse.StaticController.pages.forEach (page) ->
window.Discourse["#{page.capitalize()}Route"] = Discourse.Route.extend
renderTemplate: -> @render 'static'
setupController: -> @controllerFor('static').loadPath("/#{page}")
renderTemplate: -> @render 'static'
setupController: -> @controllerFor('static').loadPath("/#{page}")

View File

@ -4,4 +4,4 @@ window.Discourse.TopicFromParamsRoute = Discourse.Route.extend
params.trackVisit = true
topicController = @controllerFor('topic')
topicController.cancelFilter()
@modelFor('topic').loadPosts(params)
@modelFor('topic').loadPosts(params)

View File

@ -18,4 +18,4 @@ window.Discourse.TopicRoute = Discourse.Route.extend
setupController: (controller, model) ->
controller.set('showExtraHeaderInfo', false)
headerController = @controllerFor('header')
headerController?.set('topic', model)
headerController?.set('topic', model)

View File

@ -5,4 +5,4 @@ window.Discourse.UserActivityRoute = Discourse.Route.extend
setupController: (controller) ->
userController = @controllerFor('user')
userController.set('filter', null) # clear filter
controller.set('content', userController.get('content'))
controller.set('content', userController.get('content'))

View File

@ -4,4 +4,4 @@ window.Discourse.UserInvitedRoute = Discourse.Route.extend
setupController: (controller) ->
Discourse.InviteList.findInvitedBy(@controllerFor('user').get('content')).then (invited) =>
controller.set('content', invited)
controller.set('content', invited)

View File

@ -5,7 +5,7 @@ window.Discourse.UserPrivateMessagesRoute = Discourse.Route.extend
user = @controllerFor('user').get('content')
controller.set('content', user)
user.filterStream(13)
Discourse.Draft.get('new_private_message').then (data)=>
if data.draft
@controllerFor('composer').open

View File

@ -1,3 +1,3 @@
window.Discourse.UserRoute = Discourse.Route.extend
model: (params) -> Discourse.User.find(params.username)
serialize: (params) -> username: Em.get(params, 'username').toLowerCase()
serialize: (params) -> username: Em.get(params, 'username').toLowerCase()

View File

@ -1,3 +1,3 @@
window.Discourse.ArchetypeOptionsModalView = window.Discourse.ModalBodyView.extend
templateName: 'modal/archetype_options'
title: Em.String.i18n('topic.options')
title: Em.String.i18n('topic.options')

View File

@ -1,7 +1,7 @@
Discourse.AutoSizedTextView = Ember.View.extend
render: (buffer)->
null
didInsertElement: (e) ->
me = @$()
me.text(@get('content'))
@ -13,6 +13,6 @@ Discourse.AutoSizedTextView = Ember.View.extend
lh -=1
me.css("font-size", "#{fontSize}px")
me.css("line-height", "#{lh}px")

View File

@ -5,4 +5,4 @@ window.Discourse.ComboboxViewCategory = Discourse.ComboboxView.extend
template: (text, templateData) ->
return text unless templateData.color
"<span class='badge-category' style='background-color: ##{templateData.color}'>#{text}</span>"
"<span class='badge-category' style='background-color: ##{templateData.color}'>#{text}</span>"

View File

@ -54,7 +54,7 @@ window.Discourse.ComposerView = window.Discourse.View.extend
willDestroyElement: ->
$('body').off 'keydown.composer'
resize: (->
# this still needs to wait on animations, need a clean way to do that
Em.run.next null, =>
@ -91,13 +91,13 @@ window.Discourse.ComposerView = window.Discourse.View.extend
initEditor: ->
# not quite right, need a callback to pass in, meaning this gets called once,
# not quite right, need a callback to pass in, meaning this gets called once,
# but if you start replying to another topic it will get the avatars wrong
@wmdInput = $wmdInput = $('#wmd-input')
return if $wmdInput.length == 0 || $wmdInput.data('init') == true
Discourse.ComposerView.trigger("initWmdEditor")
template = Handlebars.compile("<div class='autocomplete'>
<ul>
{{#each options}}
@ -152,7 +152,7 @@ window.Discourse.ComposerView = window.Discourse.View.extend
@editor.hooks.onPreviewRefresh = => @afterRender()
@editor.run()
@set('editor', @editor)
@loadingChanged()
saveDraft = Discourse.debounce((=> @get('controller').saveDraft()),2000)
@ -165,7 +165,7 @@ window.Discourse.ComposerView = window.Discourse.View.extend
saveDraft()
return true
# In case it's still bound somehow
# In case it's still bound somehow
$uploadTarget.fileupload('destroy')
# Add the upload action
@ -200,13 +200,13 @@ window.Discourse.ComposerView = window.Discourse.View.extend
@set('loadingImage', false)
# I hate to use Em.run.later, but I don't think there's a way of waiting for a CSS transition
# I hate to use Em.run.later, but I don't think there's a way of waiting for a CSS transition
# to finish.
Em.run.later($, (=>
replyTitle = $('#reply-title')
@resize()
if replyTitle.length
replyTitle.putCursorAtEnd()
else
@ -242,7 +242,7 @@ Discourse.NotifyingTextArea = Ember.TextArea.extend
placeholder: (->
Em.String.i18n(@get('placeholderKey'))
).property('placeholderKey')
didInsertElement: ->
@get('parent').childDidInsertElement(@)

View File

@ -7,7 +7,7 @@ window.Discourse.ExcerptCategoryView = Ember.View.extend
cat = @get('category')
cat.set('id', cat.get('slug'))
@get('controller.controllers.modal')?.showView(Discourse.EditCategoryView.create(category: cat))
@get('controller.controllers.modal')?.showView(Discourse.EditCategoryView.create(category: cat))
false
deleteCategory: ->
@ -16,8 +16,8 @@ window.Discourse.ExcerptCategoryView = Ember.View.extend
bootbox.confirm Em.String.i18n("category.delete_confirm"), (result) =>
if result
@get('category').delete ->
Discourse.get('appController').reloadSession -> Discourse.get('router').route("/categories")
Discourse.get('appController').reloadSession -> Discourse.get('router').route("/categories")
false
didInsertElement: ->

View File

@ -6,7 +6,7 @@ window.Discourse.ExcerptUserView = Ember.View.extend
url = post.get("url")
username = post.get("username")
Discourse.router.route('/users/' + Discourse.currentUser.username.toLowerCase() + "/private-messages")
# TODO figure out a way for it to open the composer cleanly AFTER the navigation happens.
composerController = Discourse.get('router.composerController')
composerController.open

View File

@ -91,7 +91,7 @@ window.Discourse.ExcerptView = Ember.ContainerView.extend
didInsertElement: ->
# lets disable this puppy for now, it looks unprofessional
# lets disable this puppy for now, it looks unprofessional
return
# We don't do hovering on touch devices
@ -120,7 +120,7 @@ window.Discourse.ExcerptView = Ember.ContainerView.extend
topPosY = (pos.top - height) - margin
bottomPosY = (pos.top + margin)
# Switch to right if there's no room on top
if positionText == 'top'
positionText = 'bottom' if topPosY < 10
@ -140,7 +140,7 @@ window.Discourse.ExcerptView = Ember.ContainerView.extend
if (pos.left || 0) <= 0 && (pos.top || 0) <= 0
# somehow, sometimes, we are trying to position stuff in weird spots, just skip it
return
@set('position', positionText)
@set('desiredLocation', pos)
@set('size', $target.data('excerpt-size'))
@ -150,5 +150,5 @@ window.Discourse.ExcerptView = Ember.ContainerView.extend
$('#main').on 'mouseleave', '.excerptable', (e) =>
Em.run.cancel(@openTimer)
@closeSoon()

View File

@ -1,7 +1,7 @@
window.Discourse.FeaturedTopicsView = Ember.View.extend
templateName: 'featured_topics'
classNames: ['category-list-item']
classNames: ['category-list-item']
init: ->
@._super()
@set('context', @get('content'))
@set('context', @get('content'))

View File

@ -9,13 +9,13 @@ window.Discourse.FlagView = Ember.View.extend
@set('isCustomFlag', action.is_custom_flag)
Em.run.next -> $("#radio_#{action.name_key}").prop('checked', 'true')
false
createFlag: ->
actionType = Discourse.get("site").postActionTypeById(@get('postActionTypeId'))
@get("post.actionByName.#{actionType.get('name_key')}")?.act(message: @get('customFlagMessage'))
$('#discourse-modal').modal('hide')
false
customPlaceholder: (->
Em.String.i18n("flagging.custom_placeholder")
).property()

View File

@ -7,7 +7,7 @@ window.Discourse.HeaderView = Ember.View.extend
currentUserBinding: 'Discourse.currentUser'
categoriesBinding: 'site.categories'
topicBinding: 'Discourse.router.topicController.content'
showDropdown: ($target) ->
elementId = $target.data('dropdown') || $target.data('notifications')
$dropdown = $("##{elementId}")
@ -31,7 +31,7 @@ window.Discourse.HeaderView = Ember.View.extend
$html.on 'click.d-dropdown touchstart.d-dropdown', (e) =>
return true if $(e.target).closest('.d-dropdown').length > 0
hideDropdown()
$html.data('hide-dropdown', hideDropdown)
false
@ -65,7 +65,7 @@ window.Discourse.HeaderView = Ember.View.extend
if @dockedHeader
$('body').removeClass('docked')
@dockedHeader = false
willDestroyElement: ->
$(window).unbind 'scroll.discourse-dock'
@ -75,7 +75,7 @@ window.Discourse.HeaderView = Ember.View.extend
didInsertElement: ->
@.$('a[data-dropdown]').on 'click touchstart', (e) => @showDropdown($(e.currentTarget))
@.$('a.unread-private-messages, a.unread-notifications, a[data-notifications]').on 'click touchstart', (e) => @showNotifications(e)
$(window).bind 'scroll.discourse-dock', => @examineDockHeader()
$(document).bind 'touchmove.discourse-dock', => @examineDockHeader()
@examineDockHeader()
@ -86,7 +86,7 @@ window.Discourse.HeaderView = Ember.View.extend
# Hide dropdowns
if e.which == 27
@.$('li').removeClass('active')
@.$('.d-dropdown').fadeOut('fast')
@.$('.d-dropdown').fadeOut('fast')
if @get('editingTopic')
@finishedEdit() if e.which == 13

View File

@ -25,9 +25,9 @@ window.Discourse.HistoryView = Ember.View.extend
@get('originalPost').loadVersions (result) =>
@set('loading', false)
@set('versionLeft', result.first())
@set('versionRight', result.last())
@set('versions', result)

View File

@ -2,14 +2,14 @@ window.Discourse.ImageSelectorView = Ember.View.extend
templateName: 'image_selector'
classNames: ['image-selector']
title: 'Insert Image'
init: ->
@._super()
@set('localSelected', true)
selectLocal: ->
@set('localSelected', true)
selectRemote: ->
@set('localSelected', false)
@ -26,6 +26,6 @@ window.Discourse.ImageSelectorView = Ember.View.extend
add: ->
@get('composer').addMarkdown("![image](#{$('#fileurl-input').val()})")
$('#discourse-modal').modal('hide')

View File

@ -17,4 +17,4 @@ Discourse.InputTipView = Ember.View.extend Discourse.Presence,
render: (buffer) ->
if reason = @get('validation.reason')
icon = if @get('good') then 'icon-ok' else 'icon-remove'
buffer.push "<i class=\"icon #{icon}\"></i> #{reason}"
buffer.push "<i class=\"icon #{icon}\"></i> #{reason}"

Some files were not shown because too many files have changed in this diff Show More