FIX: Don't show similar topics with no results
This commit is contained in:
parent
c04b214910
commit
b8ef93e0a1
|
@ -271,11 +271,8 @@ export default DiscourseController.extend({
|
||||||
// We don't care about similar topics unless creating a topic
|
// We don't care about similar topics unless creating a topic
|
||||||
if (!this.get('model.creatingTopic')) { return; }
|
if (!this.get('model.creatingTopic')) { return; }
|
||||||
|
|
||||||
let body = this.get('model.reply'),
|
let body = this.get('model.reply');
|
||||||
message;
|
const title = this.get('model.title');
|
||||||
|
|
||||||
const title = this.get('model.title'),
|
|
||||||
self = this;
|
|
||||||
|
|
||||||
// Ensure the fields are of the minimum length
|
// Ensure the fields are of the minimum length
|
||||||
if (body.length < Discourse.SiteSettings.min_body_similar_length) { return; }
|
if (body.length < Discourse.SiteSettings.min_body_similar_length) { return; }
|
||||||
|
@ -291,24 +288,24 @@ export default DiscourseController.extend({
|
||||||
const messageController = this.get('controllers.composer-messages'),
|
const messageController = this.get('controllers.composer-messages'),
|
||||||
similarTopics = this.get('similarTopics');
|
similarTopics = this.get('similarTopics');
|
||||||
|
|
||||||
|
let message = this.get('similarTopicsMessage');
|
||||||
|
if (!message) {
|
||||||
|
message = Discourse.ComposerMessage.create({
|
||||||
|
templateName: 'composer/similar_topics',
|
||||||
|
extraClass: 'similar-topics'
|
||||||
|
});
|
||||||
|
this.set('similarTopicsMessage', message);
|
||||||
|
}
|
||||||
|
|
||||||
Discourse.Topic.findSimilarTo(title, body).then(function (newTopics) {
|
Discourse.Topic.findSimilarTo(title, body).then(function (newTopics) {
|
||||||
similarTopics.clear();
|
similarTopics.clear();
|
||||||
similarTopics.pushObjects(newTopics);
|
similarTopics.pushObjects(newTopics);
|
||||||
|
|
||||||
if (similarTopics.get('length') > 0) {
|
if (similarTopics.get('length') > 0) {
|
||||||
message = Discourse.ComposerMessage.create({
|
message.set('similarTopics', similarTopics);
|
||||||
templateName: 'composer/similar_topics',
|
|
||||||
similarTopics,
|
|
||||||
extraClass: 'similar-topics'
|
|
||||||
});
|
|
||||||
|
|
||||||
self.set('similarTopicsMessage', message);
|
|
||||||
messageController.send("popup", message);
|
messageController.send("popup", message);
|
||||||
} else {
|
} else if (message) {
|
||||||
message = self.get('similarTopicsMessage');
|
messageController.send("hideMessage", message);
|
||||||
if (message) {
|
|
||||||
messageController.send("hideMessage", message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
import userSearch from 'discourse/lib/user-search';
|
import userSearch from 'discourse/lib/user-search';
|
||||||
import afterTransition from 'discourse/lib/after-transition';
|
import afterTransition from 'discourse/lib/after-transition';
|
||||||
|
|
||||||
var ComposerView = Discourse.View.extend(Ember.Evented, {
|
const ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
|
_lastKeyTimeout: null,
|
||||||
templateName: 'composer',
|
templateName: 'composer',
|
||||||
elementId: 'reply-control',
|
elementId: 'reply-control',
|
||||||
classNameBindings: ['model.creatingPrivateMessage:private-message',
|
classNameBindings: ['model.creatingPrivateMessage:private-message',
|
||||||
|
@ -48,12 +49,12 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
Ember.run.scheduleOnce('afterRender', this, 'refreshPreview');
|
Ember.run.scheduleOnce('afterRender', this, 'refreshPreview');
|
||||||
}.observes('model.reply', 'model.hidePreview'),
|
}.observes('model.reply', 'model.hidePreview'),
|
||||||
|
|
||||||
focusIn: function() {
|
focusIn() {
|
||||||
var controller = this.get('controller');
|
const controller = this.get('controller');
|
||||||
if (controller) controller.updateDraftStatus();
|
if (controller) controller.updateDraftStatus();
|
||||||
},
|
},
|
||||||
|
|
||||||
movePanels: function(sizePx) {
|
movePanels(sizePx) {
|
||||||
$('#main-outlet').css('padding-bottom', sizePx);
|
$('#main-outlet').css('padding-bottom', sizePx);
|
||||||
$('.composer-popup').css('bottom', sizePx);
|
$('.composer-popup').css('bottom', sizePx);
|
||||||
// signal the progress bar it should move!
|
// signal the progress bar it should move!
|
||||||
|
@ -61,14 +62,14 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
},
|
},
|
||||||
|
|
||||||
resize: function() {
|
resize: function() {
|
||||||
var self = this;
|
const self = this;
|
||||||
Em.run.scheduleOnce('afterRender', function() {
|
Em.run.scheduleOnce('afterRender', function() {
|
||||||
var h = $('#reply-control').height() || 0;
|
const h = $('#reply-control').height() || 0;
|
||||||
self.movePanels.apply(self, [h + "px"]);
|
self.movePanels.apply(self, [h + "px"]);
|
||||||
|
|
||||||
// Figure out the size of the fields
|
// Figure out the size of the fields
|
||||||
var $fields = self.$('.composer-fields'),
|
const $fields = self.$('.composer-fields');
|
||||||
pos = $fields.position();
|
let pos = $fields.position();
|
||||||
|
|
||||||
if (pos) {
|
if (pos) {
|
||||||
self.$('.wmd-controls').css('top', $fields.height() + pos.top + 5);
|
self.$('.wmd-controls').css('top', $fields.height() + pos.top + 5);
|
||||||
|
@ -83,17 +84,19 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
});
|
});
|
||||||
}.observes('model.composeState', 'model.action'),
|
}.observes('model.composeState', 'model.action'),
|
||||||
|
|
||||||
keyUp: function() {
|
keyUp() {
|
||||||
var controller = this.get('controller');
|
const controller = this.get('controller');
|
||||||
controller.checkReplyLength();
|
controller.checkReplyLength();
|
||||||
|
|
||||||
var lastKeyUp = new Date();
|
const lastKeyUp = new Date();
|
||||||
this.set('lastKeyUp', lastKeyUp);
|
this.set('lastKeyUp', lastKeyUp);
|
||||||
|
|
||||||
// One second from now, check to see if the last key was hit when
|
// One second from now, check to see if the last key was hit when
|
||||||
// we recorded it. If it was, the user paused typing.
|
// we recorded it. If it was, the user paused typing.
|
||||||
var self = this;
|
const self = this;
|
||||||
Em.run.later(function() {
|
|
||||||
|
Ember.run.cancel(this._lastKeyTimeout);
|
||||||
|
this._lastKeyTimeout = Ember.run.later(function() {
|
||||||
if (lastKeyUp !== self.get('lastKeyUp')) return;
|
if (lastKeyUp !== self.get('lastKeyUp')) return;
|
||||||
|
|
||||||
// Search for similar topics if the user pauses typing
|
// Search for similar topics if the user pauses typing
|
||||||
|
@ -101,7 +104,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
},
|
},
|
||||||
|
|
||||||
keyDown: function(e) {
|
keyDown(e) {
|
||||||
if (e.which === 27) {
|
if (e.which === 27) {
|
||||||
// ESC
|
// ESC
|
||||||
this.get('controller').send('hitEsc');
|
this.get('controller').send('hitEsc');
|
||||||
|
@ -114,12 +117,12 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
},
|
},
|
||||||
|
|
||||||
_enableResizing: function() {
|
_enableResizing: function() {
|
||||||
var $replyControl = $('#reply-control'),
|
const $replyControl = $('#reply-control'),
|
||||||
self = this;
|
self = this;
|
||||||
|
|
||||||
$replyControl.DivResizer({
|
$replyControl.DivResizer({
|
||||||
resize: this.resize.bind(self),
|
resize: this.resize.bind(self),
|
||||||
onDrag: function (sizePx) { self.movePanels.apply(self, [sizePx]); }
|
onDrag(sizePx) { self.movePanels.apply(self, [sizePx]); }
|
||||||
});
|
});
|
||||||
afterTransition($replyControl, this.resize.bind(self));
|
afterTransition($replyControl, this.resize.bind(self));
|
||||||
this.ensureMaximumDimensionForImagesInPreview();
|
this.ensureMaximumDimensionForImagesInPreview();
|
||||||
|
@ -130,14 +133,14 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
this.set('controller.view', null);
|
this.set('controller.view', null);
|
||||||
}.on('willDestroyElement'),
|
}.on('willDestroyElement'),
|
||||||
|
|
||||||
ensureMaximumDimensionForImagesInPreview: function() {
|
ensureMaximumDimensionForImagesInPreview() {
|
||||||
// This enforce maximum dimensions of images in the preview according
|
// This enforce maximum dimensions of images in the preview according
|
||||||
// to the current site settings.
|
// to the current site settings.
|
||||||
// For interactivity, we immediately insert the locally cooked version
|
// For interactivity, we immediately insert the locally cooked version
|
||||||
// of the post into the stream when the user hits reply. We therefore also
|
// of the post into the stream when the user hits reply. We therefore also
|
||||||
// need to enforce these rules on the .cooked version.
|
// need to enforce these rules on the .cooked version.
|
||||||
// Meanwhile, the server is busy post-processing the post and generating thumbnails.
|
// Meanwhile, the server is busy post-processing the post and generating thumbnails.
|
||||||
var style = Discourse.Mobile.mobileView ?
|
const style = Discourse.Mobile.mobileView ?
|
||||||
'max-width: 100%; height: auto;' :
|
'max-width: 100%; height: auto;' :
|
||||||
'max-width:' + Discourse.SiteSettings.max_image_width + 'px;' +
|
'max-width:' + Discourse.SiteSettings.max_image_width + 'px;' +
|
||||||
'max-height:' + Discourse.SiteSettings.max_image_height + 'px;';
|
'max-height:' + Discourse.SiteSettings.max_image_height + 'px;';
|
||||||
|
@ -145,17 +148,17 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
$('<style>#wmd-preview img:not(.thumbnail), .cooked img:not(.thumbnail) {' + style + '}</style>').appendTo('head');
|
$('<style>#wmd-preview img:not(.thumbnail), .cooked img:not(.thumbnail) {' + style + '}</style>').appendTo('head');
|
||||||
},
|
},
|
||||||
|
|
||||||
click: function() {
|
click() {
|
||||||
this.get('controller').send('openIfDraft');
|
this.get('controller').send('openIfDraft');
|
||||||
},
|
},
|
||||||
|
|
||||||
// Called after the preview renders. Debounced for performance
|
// Called after the preview renders. Debounced for performance
|
||||||
afterRender: function() {
|
afterRender() {
|
||||||
var $wmdPreview = $('#wmd-preview');
|
const $wmdPreview = $('#wmd-preview');
|
||||||
if ($wmdPreview.length === 0) return;
|
if ($wmdPreview.length === 0) return;
|
||||||
|
|
||||||
var post = this.get('model.post'),
|
const post = this.get('model.post');
|
||||||
refresh = false;
|
let refresh = false;
|
||||||
|
|
||||||
// If we are editing a post, we'll refresh its contents once. This is a feature that
|
// If we are editing a post, we'll refresh its contents once. This is a feature that
|
||||||
// allows a user to refresh its contents once.
|
// allows a user to refresh its contents once.
|
||||||
|
@ -175,17 +178,17 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
this.trigger('previewRefreshed', $wmdPreview);
|
this.trigger('previewRefreshed', $wmdPreview);
|
||||||
},
|
},
|
||||||
|
|
||||||
_applyEmojiAutocomplete: function() {
|
_applyEmojiAutocomplete() {
|
||||||
if (!this.siteSettings.enable_emoji) { return; }
|
if (!this.siteSettings.enable_emoji) { return; }
|
||||||
|
|
||||||
var template = this.container.lookup('template:emoji-selector-autocomplete.raw');
|
const template = this.container.lookup('template:emoji-selector-autocomplete.raw');
|
||||||
$('#wmd-input').autocomplete({
|
$('#wmd-input').autocomplete({
|
||||||
template: template,
|
template: template,
|
||||||
key: ":",
|
key: ":",
|
||||||
transformComplete: function(v){ return v.code + ":"; },
|
transformComplete(v) { return v.code + ":"; },
|
||||||
dataSource: function(term){
|
dataSource(term){
|
||||||
return new Ember.RSVP.Promise(function(resolve) {
|
return new Ember.RSVP.Promise(function(resolve) {
|
||||||
var full = ":" + term;
|
const full = ":" + term;
|
||||||
term = term.toLowerCase();
|
term = term.toLowerCase();
|
||||||
|
|
||||||
if (term === "") {
|
if (term === "") {
|
||||||
|
@ -196,7 +199,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
return resolve([Discourse.Emoji.translations[full]]);
|
return resolve([Discourse.Emoji.translations[full]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = Discourse.Emoji.search(term, {maxResults: 5});
|
const options = Discourse.Emoji.search(term, {maxResults: 5});
|
||||||
|
|
||||||
return resolve(options);
|
return resolve(options);
|
||||||
}).then(function(list) {
|
}).then(function(list) {
|
||||||
|
@ -208,10 +211,11 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
initEditor: function() {
|
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
|
// but if you start replying to another topic it will get the avatars wrong
|
||||||
var $wmdInput, editor, self = this;
|
let $wmdInput, editor;
|
||||||
|
const self = this;
|
||||||
this.wmdInput = $wmdInput = $('#wmd-input');
|
this.wmdInput = $wmdInput = $('#wmd-input');
|
||||||
if ($wmdInput.length === 0 || $wmdInput.data('init') === true) return;
|
if ($wmdInput.length === 0 || $wmdInput.data('init') === true) return;
|
||||||
|
|
||||||
|
@ -219,11 +223,11 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
ComposerView.trigger("initWmdEditor");
|
ComposerView.trigger("initWmdEditor");
|
||||||
this._applyEmojiAutocomplete();
|
this._applyEmojiAutocomplete();
|
||||||
|
|
||||||
var template = this.container.lookup('template:user-selector-autocomplete.raw');
|
const template = this.container.lookup('template:user-selector-autocomplete.raw');
|
||||||
$wmdInput.data('init', true);
|
$wmdInput.data('init', true);
|
||||||
$wmdInput.autocomplete({
|
$wmdInput.autocomplete({
|
||||||
template: template,
|
template: template,
|
||||||
dataSource: function(term) {
|
dataSource(term) {
|
||||||
return userSearch({
|
return userSearch({
|
||||||
term: term,
|
term: term,
|
||||||
topicId: self.get('controller.controllers.topic.model.id'),
|
topicId: self.get('controller.controllers.topic.model.id'),
|
||||||
|
@ -231,7 +235,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
key: "@",
|
key: "@",
|
||||||
transformComplete: function(v) {
|
transformComplete(v) {
|
||||||
if (v.username) {
|
if (v.username) {
|
||||||
return v.username;
|
return v.username;
|
||||||
} else {
|
} else {
|
||||||
|
@ -241,10 +245,10 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.editor = editor = Discourse.Markdown.createEditor({
|
this.editor = editor = Discourse.Markdown.createEditor({
|
||||||
lookupAvatarByPostNumber: function(postNumber) {
|
lookupAvatarByPostNumber(postNumber) {
|
||||||
var posts = self.get('controller.controllers.topic.postStream.posts');
|
const posts = self.get('controller.controllers.topic.postStream.posts');
|
||||||
if (posts) {
|
if (posts) {
|
||||||
var quotedPost = posts.findProperty("post_number", postNumber);
|
const quotedPost = posts.findProperty("post_number", postNumber);
|
||||||
if (quotedPost) {
|
if (quotedPost) {
|
||||||
return Discourse.Utilities.tinyAvatar(quotedPost.get("avatar_template"));
|
return Discourse.Utilities.tinyAvatar(quotedPost.get("avatar_template"));
|
||||||
}
|
}
|
||||||
|
@ -273,7 +277,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
this.set('editor', this.editor);
|
this.set('editor', this.editor);
|
||||||
this.loadingChanged();
|
this.loadingChanged();
|
||||||
|
|
||||||
var saveDraft = Discourse.debounce((function() {
|
const saveDraft = Discourse.debounce((function() {
|
||||||
return self.get('controller').saveDraft();
|
return self.get('controller').saveDraft();
|
||||||
}), 2000);
|
}), 2000);
|
||||||
|
|
||||||
|
@ -282,7 +286,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
var $replyTitle = $('#reply-title');
|
const $replyTitle = $('#reply-title');
|
||||||
|
|
||||||
$replyTitle.keyup(function() {
|
$replyTitle.keyup(function() {
|
||||||
saveDraft();
|
saveDraft();
|
||||||
|
@ -305,9 +309,9 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
// in case it's still bound somehow
|
// in case it's still bound somehow
|
||||||
this._unbindUploadTarget();
|
this._unbindUploadTarget();
|
||||||
|
|
||||||
var $uploadTarget = $('#reply-control'),
|
const $uploadTarget = $('#reply-control'),
|
||||||
csrf = Discourse.Session.currentProp('csrfToken'),
|
csrf = Discourse.Session.currentProp('csrfToken');
|
||||||
cancelledByTheUser;
|
let cancelledByTheUser;
|
||||||
|
|
||||||
// NOTE: we need both the .json extension and the CSRF token as a query parameter for IE9
|
// NOTE: we need both the .json extension and the CSRF token as a query parameter for IE9
|
||||||
$uploadTarget.fileupload({
|
$uploadTarget.fileupload({
|
||||||
|
@ -318,7 +322,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
|
|
||||||
// submit - this event is triggered for each upload
|
// submit - this event is triggered for each upload
|
||||||
$uploadTarget.on('fileuploadsubmit', function (e, data) {
|
$uploadTarget.on('fileuploadsubmit', function (e, data) {
|
||||||
var result = Discourse.Utilities.validateUploadedFiles(data.files);
|
const result = Discourse.Utilities.validateUploadedFiles(data.files);
|
||||||
// reset upload status when everything is ok
|
// reset upload status when everything is ok
|
||||||
if (result) self.setProperties({ uploadProgress: 0, isUploading: true });
|
if (result) self.setProperties({ uploadProgress: 0, isUploading: true });
|
||||||
return result;
|
return result;
|
||||||
|
@ -331,7 +335,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
self.get('controller').send('closeModal');
|
self.get('controller').send('closeModal');
|
||||||
// NOTE: IE9 doesn't support XHR
|
// NOTE: IE9 doesn't support XHR
|
||||||
if (data["xhr"]) {
|
if (data["xhr"]) {
|
||||||
var jqHXR = data.xhr();
|
const jqHXR = data.xhr();
|
||||||
if (jqHXR) {
|
if (jqHXR) {
|
||||||
// need to wait for the link to show up in the DOM
|
// need to wait for the link to show up in the DOM
|
||||||
Em.run.schedule('afterRender', function() {
|
Em.run.schedule('afterRender', function() {
|
||||||
|
@ -351,7 +355,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
|
|
||||||
// progress all
|
// progress all
|
||||||
$uploadTarget.on('fileuploadprogressall', function (e, data) {
|
$uploadTarget.on('fileuploadprogressall', function (e, data) {
|
||||||
var progress = parseInt(data.loaded / data.total * 100, 10);
|
const progress = parseInt(data.loaded / data.total * 100, 10);
|
||||||
self.set('uploadProgress', progress);
|
self.set('uploadProgress', progress);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -360,7 +364,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
if (!cancelledByTheUser) {
|
if (!cancelledByTheUser) {
|
||||||
// make sure we have a url
|
// make sure we have a url
|
||||||
if (data.result.url) {
|
if (data.result.url) {
|
||||||
var markdown = Discourse.Utilities.getUploadMarkdown(data.result);
|
const markdown = Discourse.Utilities.getUploadMarkdown(data.result);
|
||||||
// appends a space at the end of the inserted markdown
|
// appends a space at the end of the inserted markdown
|
||||||
self.addMarkdown(markdown + " ");
|
self.addMarkdown(markdown + " ");
|
||||||
self.set('isUploading', false);
|
self.set('isUploading', false);
|
||||||
|
@ -385,7 +389,7 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
// Firefox. This is pretty dangerous because it can potentially break
|
// Firefox. This is pretty dangerous because it can potentially break
|
||||||
// Ctrl+v to paste so we should be conservative about what browsers this runs
|
// Ctrl+v to paste so we should be conservative about what browsers this runs
|
||||||
// in.
|
// in.
|
||||||
var uaMatch = navigator.userAgent.match(/Firefox\/(\d+)\.\d/);
|
const uaMatch = navigator.userAgent.match(/Firefox\/(\d+)\.\d/);
|
||||||
if (uaMatch && parseInt(uaMatch[1]) >= 24) {
|
if (uaMatch && parseInt(uaMatch[1]) >= 24) {
|
||||||
self.$().append( Ember.$("<div id='contenteditable' contenteditable='true' style='height: 0; width: 0; overflow: hidden'></div>") );
|
self.$().append( Ember.$("<div id='contenteditable' contenteditable='true' style='height: 0; width: 0; overflow: hidden'></div>") );
|
||||||
self.$("textarea").off('keydown.contenteditable');
|
self.$("textarea").off('keydown.contenteditable');
|
||||||
|
@ -395,18 +399,18 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
// after we switch focus, probably because it is being executed too late.
|
// after we switch focus, probably because it is being executed too late.
|
||||||
if ((event.ctrlKey || event.metaKey) && (event.keyCode === 86)) {
|
if ((event.ctrlKey || event.metaKey) && (event.keyCode === 86)) {
|
||||||
// Save the current textarea selection.
|
// Save the current textarea selection.
|
||||||
var textarea = self.$("textarea")[0],
|
const textarea = self.$("textarea")[0],
|
||||||
selectionStart = textarea.selectionStart,
|
selectionStart = textarea.selectionStart,
|
||||||
selectionEnd = textarea.selectionEnd;
|
selectionEnd = textarea.selectionEnd;
|
||||||
|
|
||||||
// Focus the contenteditable div.
|
// Focus the contenteditable div.
|
||||||
var contentEditableDiv = self.$('#contenteditable');
|
const contentEditableDiv = self.$('#contenteditable');
|
||||||
contentEditableDiv.focus();
|
contentEditableDiv.focus();
|
||||||
|
|
||||||
// The paste doesn't finish immediately and we don't have any onpaste
|
// The paste doesn't finish immediately and we don't have any onpaste
|
||||||
// event, so wait for 100ms which _should_ be enough time.
|
// event, so wait for 100ms which _should_ be enough time.
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var pastedImg = contentEditableDiv.find('img');
|
const pastedImg = contentEditableDiv.find('img');
|
||||||
|
|
||||||
if ( pastedImg.length === 1 ) {
|
if ( pastedImg.length === 1 ) {
|
||||||
pastedImg.remove();
|
pastedImg.remove();
|
||||||
|
@ -414,11 +418,11 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
|
|
||||||
// For restoring the selection.
|
// For restoring the selection.
|
||||||
textarea.focus();
|
textarea.focus();
|
||||||
var textareaContent = $(textarea).val(),
|
const textareaContent = $(textarea).val(),
|
||||||
startContent = textareaContent.substring(0, selectionStart),
|
startContent = textareaContent.substring(0, selectionStart),
|
||||||
endContent = textareaContent.substring(selectionEnd);
|
endContent = textareaContent.substring(selectionEnd);
|
||||||
|
|
||||||
var restoreSelection = function(pastedText) {
|
const restoreSelection = function(pastedText) {
|
||||||
$(textarea).val( startContent + pastedText + endContent );
|
$(textarea).val( startContent + pastedText + endContent );
|
||||||
textarea.selectionStart = selectionStart + pastedText.length;
|
textarea.selectionStart = selectionStart + pastedText.length;
|
||||||
textarea.selectionEnd = textarea.selectionStart;
|
textarea.selectionEnd = textarea.selectionStart;
|
||||||
|
@ -435,20 +439,20 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
// to a Blob and upload that, but if it is a regular URL that
|
// to a Blob and upload that, but if it is a regular URL that
|
||||||
// operation is prevented for security purposes. When we get a regular
|
// operation is prevented for security purposes. When we get a regular
|
||||||
// URL let's just create an <img> tag for the image.
|
// URL let's just create an <img> tag for the image.
|
||||||
var imageSrc = pastedImg.attr('src');
|
const imageSrc = pastedImg.attr('src');
|
||||||
|
|
||||||
if (imageSrc.match(/^data:image/)) {
|
if (imageSrc.match(/^data:image/)) {
|
||||||
// Restore the cursor position, and remove any selected text.
|
// Restore the cursor position, and remove any selected text.
|
||||||
restoreSelection("");
|
restoreSelection("");
|
||||||
|
|
||||||
// Create a Blob to upload.
|
// Create a Blob to upload.
|
||||||
var image = new Image();
|
const image = new Image();
|
||||||
image.onload = function() {
|
image.onload = function() {
|
||||||
// Create a new canvas.
|
// Create a new canvas.
|
||||||
var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
|
const canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
|
||||||
canvas.height = image.height;
|
canvas.height = image.height;
|
||||||
canvas.width = image.width;
|
canvas.width = image.width;
|
||||||
var ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.drawImage(image, 0, 0);
|
ctx.drawImage(image, 0, 0);
|
||||||
|
|
||||||
canvas.toBlob(function(blob) {
|
canvas.toBlob(function(blob) {
|
||||||
|
@ -488,8 +492,8 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
}, 400);
|
}, 400);
|
||||||
},
|
},
|
||||||
|
|
||||||
addMarkdown: function(text) {
|
addMarkdown(text) {
|
||||||
var ctrl = $('#wmd-input').get(0),
|
const ctrl = $('#wmd-input').get(0),
|
||||||
caretPosition = Discourse.Utilities.caretPosition(ctrl),
|
caretPosition = Discourse.Utilities.caretPosition(ctrl),
|
||||||
current = this.get('model.reply');
|
current = this.get('model.reply');
|
||||||
this.set('model.reply', current.substring(0, caretPosition) + text + current.substring(caretPosition, current.length));
|
this.set('model.reply', current.substring(0, caretPosition) + text + current.substring(caretPosition, current.length));
|
||||||
|
@ -500,10 +504,10 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Uses javascript to get the image sizes from the preview, if present
|
// Uses javascript to get the image sizes from the preview, if present
|
||||||
imageSizes: function() {
|
imageSizes() {
|
||||||
var result = {};
|
const result = {};
|
||||||
$('#wmd-preview img').each(function(i, e) {
|
$('#wmd-preview img').each(function(i, e) {
|
||||||
var $img = $(e),
|
const $img = $(e),
|
||||||
src = $img.prop('src');
|
src = $img.prop('src');
|
||||||
|
|
||||||
if (src && src.length) {
|
if (src && src.length) {
|
||||||
|
@ -513,12 +517,12 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
childDidInsertElement: function() {
|
childDidInsertElement() {
|
||||||
return this.initEditor();
|
return this.initEditor();
|
||||||
},
|
},
|
||||||
|
|
||||||
childWillDestroyElement: function() {
|
childWillDestroyElement() {
|
||||||
var self = this;
|
const self = this;
|
||||||
|
|
||||||
this._unbindUploadTarget();
|
this._unbindUploadTarget();
|
||||||
|
|
||||||
|
@ -532,9 +536,9 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
},
|
},
|
||||||
|
|
||||||
titleValidation: function() {
|
titleValidation: function() {
|
||||||
var titleLength = this.get('model.titleLength'),
|
const titleLength = this.get('model.titleLength'),
|
||||||
missingChars = this.get('model.missingTitleCharacters'),
|
missingChars = this.get('model.missingTitleCharacters');
|
||||||
reason;
|
let reason;
|
||||||
if( titleLength < 1 ){
|
if( titleLength < 1 ){
|
||||||
reason = I18n.t('composer.error.title_missing');
|
reason = I18n.t('composer.error.title_missing');
|
||||||
} else if( missingChars > 0 ) {
|
} else if( missingChars > 0 ) {
|
||||||
|
@ -555,9 +559,9 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
}.property('model.categoryId'),
|
}.property('model.categoryId'),
|
||||||
|
|
||||||
replyValidation: function() {
|
replyValidation: function() {
|
||||||
var replyLength = this.get('model.replyLength'),
|
const replyLength = this.get('model.replyLength'),
|
||||||
missingChars = this.get('model.missingReplyCharacters'),
|
missingChars = this.get('model.missingReplyCharacters');
|
||||||
reason;
|
let reason;
|
||||||
if( replyLength < 1 ){
|
if( replyLength < 1 ){
|
||||||
reason = I18n.t('composer.error.post_missing');
|
reason = I18n.t('composer.error.post_missing');
|
||||||
} else if( missingChars > 0 ) {
|
} else if( missingChars > 0 ) {
|
||||||
|
@ -569,8 +573,8 @@ var ComposerView = Discourse.View.extend(Ember.Evented, {
|
||||||
}
|
}
|
||||||
}.property('model.reply', 'model.replyLength', 'model.missingReplyCharacters', 'model.minimumPostLength'),
|
}.property('model.reply', 'model.replyLength', 'model.missingReplyCharacters', 'model.minimumPostLength'),
|
||||||
|
|
||||||
_unbindUploadTarget: function() {
|
_unbindUploadTarget() {
|
||||||
var $uploadTarget = $('#reply-control');
|
const $uploadTarget = $('#reply-control');
|
||||||
try { $uploadTarget.fileupload('destroy'); }
|
try { $uploadTarget.fileupload('destroy'); }
|
||||||
catch (e) { /* wasn't initialized yet */ }
|
catch (e) { /* wasn't initialized yet */ }
|
||||||
$uploadTarget.off();
|
$uploadTarget.off();
|
||||||
|
|
Loading…
Reference in New Issue