discourse/app/assets/javascripts/discourse/components/composer-title.js.es6

146 lines
4.8 KiB
JavaScript

import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
import InputValidation from 'discourse/models/input-validation';
import { load, lookupCache } from 'pretty-text/oneboxer';
import { ajax } from 'discourse/lib/ajax';
import afterTransition from 'discourse/lib/after-transition';
export default Ember.Component.extend({
classNames: ['title-input'],
watchForLink: Ember.computed.alias('composer.canEditTopicFeaturedLink'),
didInsertElement() {
this._super();
if (this.get('focusTarget') === 'title') {
const $input = this.$("input");
afterTransition(this.$().closest("#reply-control"), () => {
$input.putCursorAtEnd();
});
}
if (this.get('composer.titleLength') > 0) {
Ember.run.debounce(this, this._titleChanged, 10);
}
},
@computed('composer.titleLength', 'composer.missingTitleCharacters', 'composer.minimumTitleLength', 'lastValidatedAt')
validation(titleLength, missingTitleChars, minimumTitleLength, lastValidatedAt) {
let reason;
if (titleLength < 1) {
reason = I18n.t('composer.error.title_missing');
} else if (missingTitleChars > 0) {
reason = I18n.t('composer.error.title_too_short', {min: minimumTitleLength});
} else if (titleLength > this.siteSettings.max_topic_title_length) {
reason = I18n.t('composer.error.title_too_long', {max: this.siteSettings.max_topic_title_length});
}
if (reason) {
return InputValidation.create({ failed: true, reason, lastShownAt: lastValidatedAt });
}
},
@computed('watchForLink')
titleMaxLength() {
// maxLength gets in the way of pasting long links, so don't use it if featured links are allowed.
// Validation will display a message if titles are too long.
return this.get('watchForLink') ? null : this.siteSettings.max_topic_title_length;
},
@observes('composer.titleLength', 'watchForLink')
_titleChanged() {
if (this.get('composer.titleLength') === 0) { this.set('autoPosted', false); }
if (this.get('autoPosted') || !this.get('watchForLink')) { return; }
if (Ember.testing) {
this._checkForUrl();
} else {
Ember.run.debounce(this, this._checkForUrl, 500);
}
},
@observes('composer.replyLength')
_clearFeaturedLink() {
if (this.get('watchForLink') && this.bodyIsDefault()) {
this.set('composer.featuredLink', null);
}
},
_checkForUrl() {
if (!this.element || this.isDestroying || this.isDestroyed) { return; }
if (this.get('isAbsoluteUrl') && this.bodyIsDefault()) {
// only feature links to external sites
if (this.get('composer.title').match(new RegExp("^https?:\\/\\/" + window.location.hostname, "i"))) { return; }
// Try to onebox. If success, update post body and title.
this.set('composer.loading', true);
const link = document.createElement('a');
link.href = this.get('composer.title');
const loadOnebox = load({
elem: link,
refresh: false,
ajax,
synchronous: true,
categoryId: this.get('composer.category.id'),
topicId: this.get('composer.topic.id')
});
if (loadOnebox && loadOnebox.then) {
loadOnebox.then( () => {
const v = lookupCache(this.get('composer.title'));
this._updatePost(v ? v : link);
}).finally(() => {
this.set('composer.loading', false);
Ember.run.schedule('afterRender', () => { this.$('input').putCursorAtEnd(); });
});
} else {
this._updatePost(loadOnebox);
this.set('composer.loading', false);
Ember.run.schedule('afterRender', () => { this.$('input').putCursorAtEnd(); });
}
}
},
_updatePost(html) {
if (html) {
this.set('autoPosted', true);
this.set('composer.featuredLink', this.get('composer.title'));
const $h = $(html),
heading = $h.find('h3').length > 0 ? $h.find('h3') : $h.find('h4'),
composer = this.get('composer');
composer.appendText(this.get('composer.title'), null, {block: true});
if (heading.length > 0 && heading.text().length > 0) {
this.changeTitle(heading.text());
} else {
const firstTitle = $h.attr('title') || $h.find("[title]").attr("title");
if (firstTitle && firstTitle.length > 0) {
this.changeTitle(firstTitle);
}
}
}
},
changeTitle(val) {
if (val && val.length > 0) {
this.set('composer.title', val.trim());
}
},
@computed('composer.title', 'composer.titleLength')
isAbsoluteUrl(title, titleLength) {
return titleLength > 0 && /^(https?:)?\/\/[\w\.\-]+/i.test(title) && !/\s/.test(title);
},
bodyIsDefault() {
const reply = this.get('composer.reply')||"";
return (reply.length === 0 || (reply === (this.get("composer.category.topic_template")||"")));
}
});