This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/views/composer_view.js.coffee
2013-02-07 16:45:24 +01:00

250 lines
7.6 KiB
CoffeeScript

window.Discourse.ComposerView = window.Discourse.View.extend
templateName: 'composer'
elementId: 'reply-control'
classNameBindings: ['content.creatingPrivateMessage:private-message',
'composeState',
'content.loading',
'content.editTitle',
'postMade',
'content.creatingTopic:topic',
'content.showPreview',
'content.hidePreview']
composeState: (->
state = @get('content.composeState')
unless state
state = Discourse.Composer.CLOSED
state
).property('content.composeState')
draftStatus: (->
@$('.saving-draft').text(@get('content.draftStatus') || "")
).observes('content.draftStatus')
# Disable fields when we're loading
loadingChanged: (->
if @get('loading')
$('#wmd-input, #reply-title').prop('disabled', 'disabled')
else
$('#wmd-input, #reply-title').prop('disabled', '')
).observes('loading')
postMade: (->
return 'created-post' if @present('controller.createdPost')
null
).property('content.createdPost')
observeReplyChanges: (->
return if @get('content.hidePreview')
Ember.run.next null, =>
if @editor
@editor.refreshPreview()
# if the caret is on the last line ensure preview scrolled to bottom
caretPosition = Discourse.Utilities.caretPosition(@wmdInput[0])
unless @wmdInput.val().substring(caretPosition).match /\n/
$wmdPreview = $('#wmd-preview:visible')
if $wmdPreview.length > 0
$wmdPreview.scrollTop($wmdPreview[0].scrollHeight)
).observes('content.reply', 'content.hidePreview')
willDestroyElement: ->
$('body').off 'keydown.composer'
resize: (->
# this still needs to wait on animations, need a clean way to do that
Em.run.next null, =>
replyControl = $('#reply-control')
h = replyControl.height() || 0
$('.topic-area').css('padding-bottom', "#{h}px")
).observes('content.composeState')
didInsertElement: ->
# Delegate ESC to the composer
$('body').on 'keydown.composer', (e) =>
@get('controller').hitEsc() if e.which == 27
replyControl = $('#reply-control')
replyControl.DivResizer(resize: @resize)
Discourse.TransitionHelper.after(replyControl, @resize)
click: ->
@get('controller').click()
# Called after the preview renders. Debounced for performance
afterRender: Discourse.debounce(->
$wmdPreview = $('#wmd-preview')
return unless ($wmdPreview.length > 0)
Discourse.SyntaxHighlighting.apply($wmdPreview)
refresh = @get('controller.content.post.id') isnt undefined
$('a.onebox', $wmdPreview).each (i, e) => Discourse.Onebox.load(e, refresh)
$('span.mention', $wmdPreview).each (i, e) => Discourse.Mention.load(e, refresh)
, 100)
cancelUpload: ->
# TODO
initEditor: ->
# 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}}
<li>
<a href='#'>{{avatar this imageSize=\"tiny\"}} <span class='username'>{{this.username}}</span> <span class='name'>{{this.name}}</span></a>
</li>
{{/each}}
</ul>
</div>")
transformTemplate = Handlebars.compile("{{avatar this imageSize=\"tiny\"}} {{this.username}}")
$wmdInput.data('init', true)
$wmdInput.autocomplete
template: template
dataSource: (term,callback) =>
Discourse.UserSearch.search
term: term,
callback: callback,
topicId: @get('controller.controllers.topic.content.id')
key: "@"
transformComplete: (v) ->
v.username
selected = []
$('#private-message-users').val(@get('content.targetUsernames')).autocomplete
template: template
dataSource: (term, callback) ->
Discourse.UserSearch.search
term: term,
callback: callback,
exclude: selected
onChangeItems: (items) =>
items = $.map items, (i) -> if i.username then i.username else i
@set('content.targetUsernames', items.join(","))
selected = items
transformComplete: transformTemplate
reverseTransform: (i) -> {username: i}
topic = @get('topic')
@editor = editor = new Markdown.Editor(Discourse.Utilities.markdownConverter(
lookupAvatar: (username) ->
Discourse.Utilities.avatarImg(username: username, size: 'tiny')
sanitize: true
))
$uploadTarget = $('#reply-control')
@editor.hooks.insertImageDialog = (callback) =>
callback(null)
@get('controller.controllers.modal').show(Discourse.ImageSelectorView.create(composer: @, uploadTarget: $uploadTarget))
true
@editor.hooks.onPreviewRefresh = => @afterRender()
@editor.run()
@set('editor', @editor)
@loadingChanged()
saveDraft = Discourse.debounce((=> @get('controller').saveDraft()),2000)
$wmdInput.keyup =>
saveDraft()
return true
$('#reply-title').keyup =>
saveDraft()
return true
# In case it's still bound somehow
$uploadTarget.fileupload('destroy')
# Add the upload action
$uploadTarget.fileupload
url: '/uploads'
dataType: 'json'
timeout: 20000
formData:
topic_id: 1234
paste: (e, data) =>
if data.files.length > 0
@set('loadingImage', true)
@set('uploadProgress', 0)
true
drop: (e, data)=>
if e.originalEvent.dataTransfer.files.length == 1
@set('loadingImage', true)
@set('uploadProgress', 0)
progressall:(e,data)=>
progress = parseInt(data.loaded / data.total * 100, 10)
@set('uploadProgress', progress)
done: (e, data) =>
@set('loadingImage', false)
upload = data.result
html = "<img src=\"#{upload.url}\" width=\"#{upload.width}\" height=\"#{upload.height}\">"
@addMarkdown(html)
fail: (e, data) =>
bootbox.alert Em.String.i18n('post.errors.upload')
@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
# to finish.
Em.run.later($, (=>
replyTitle = $('#reply-title')
@resize()
if replyTitle.length
replyTitle.putCursorAtEnd()
else
$wmdInput.putCursorAtEnd()
)
, 300)
addMarkdown: (text)->
ctrl = $('#wmd-input').get(0)
caretPosition = Discourse.Utilities.caretPosition(ctrl)
current = @get('content.reply')
@set('content.reply', current.substring(0, caretPosition) + text + current.substring(caretPosition, current.length))
Em.run.next =>
Discourse.Utilities.setCaretPosition(ctrl, caretPosition + text.length)
# Uses javascript to get the image sizes from the preview, if present
imageSizes: ->
result = {}
$('#wmd-preview img').each (i, e) ->
$img = $(e)
result[$img.prop('src')] = {width: $img.width(), height: $img.height()}
result
childDidInsertElement: (e)->
@initEditor()
# not sure if this is the right way, keeping here for now, we could use a mixin perhaps
Discourse.NotifyingTextArea = Ember.TextArea.extend
placeholder: (->
Em.String.i18n(@get('placeholderKey'))
).property('placeholderKey')
didInsertElement: ->
@get('parent').childDidInsertElement(@)
RSVP.EventTarget.mixin(Discourse.ComposerView)