FEATURE: pasting a link into the title of the composer can automatically onebox it and update the title
This commit is contained in:
parent
a9acced4ca
commit
fbd8e6ed4a
|
@ -1,8 +1,11 @@
|
|||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
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';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['title-input'],
|
||||
watchForLink: Ember.computed.alias('composer.canEditTopicFeaturedLink'),
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
|
@ -26,5 +29,74 @@ export default Ember.Component.extend({
|
|||
if (reason) {
|
||||
return InputValidation.create({ failed: true, reason, lastShownAt: lastValidatedAt });
|
||||
}
|
||||
},
|
||||
|
||||
@observes('composer.titleLength')
|
||||
_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.get('composer.replyLength') === 0) {
|
||||
this.set('composer.featuredLink', null);
|
||||
}
|
||||
},
|
||||
|
||||
_checkForUrl() {
|
||||
if (this.get('isAbsoluteUrl') && (this.get('composer.reply')||"").length === 0) {
|
||||
// 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');
|
||||
|
||||
let loadOnebox = load(link, false, ajax);
|
||||
|
||||
if (loadOnebox && loadOnebox.then) {
|
||||
loadOnebox.then( () => {
|
||||
this._updatePost(lookupCache(this.get('composer.title')));
|
||||
}).finally(() => {
|
||||
this.set('composer.loading', false);
|
||||
});
|
||||
} else {
|
||||
this._updatePost(loadOnebox);
|
||||
this.set('composer.loading', false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_updatePost(html) {
|
||||
if (html) {
|
||||
this.set('autoPosted', true);
|
||||
this.set('composer.featuredLink', this.get('composer.title'));
|
||||
|
||||
const $h = $(html),
|
||||
header = $h.find('h4').length > 0 ? $h.find('h4') : $h.find('h3');
|
||||
|
||||
this.set('composer.reply', this.get('composer.title'));
|
||||
|
||||
if (header.length > 0 && header.text().length > 0) {
|
||||
this.set('composer.title', header.text().trim());
|
||||
} else {
|
||||
const filename = (this.get('composer.featuredLink')||"").split("/").pop();
|
||||
if (filename && filename.length > 0) {
|
||||
this.set('composer.title', filename.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@computed('composer.title')
|
||||
isAbsoluteUrl() {
|
||||
return this.get('composer.titleLength') > 0 && /^(https?:)?\/\/[\w\.\-]+/i.test(this.get('composer.title'));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -146,6 +146,11 @@ const Composer = RestModel.extend({
|
|||
return categoryIds === undefined || !categoryIds.length || categoryIds.indexOf(categoryId) !== -1;
|
||||
},
|
||||
|
||||
@computed('canEditTopicFeaturedLink')
|
||||
titlePlaceholder() {
|
||||
return this.get('canEditTopicFeaturedLink') ? 'composer.title_or_link_placeholder' : 'composer.title_placeholder';
|
||||
},
|
||||
|
||||
// Determine the appropriate title for this action
|
||||
actionTitle: function() {
|
||||
const topic = this.get('topic');
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
tabindex="2"
|
||||
id="reply-title"
|
||||
maxLength=siteSettings.max_topic_title_length
|
||||
placeholderKey="composer.title_placeholder"
|
||||
placeholderKey=composer.titlePlaceholder
|
||||
disabled=composer.loading}}
|
||||
|
||||
{{popup-input-tip validation=validation}}
|
||||
|
|
|
@ -80,11 +80,6 @@
|
|||
{{/if}}
|
||||
{{render "additional-composer-buttons" model}}
|
||||
{{/if}}
|
||||
{{#if model.canEditTopicFeaturedLink}}
|
||||
<div class="topic-featured-link-input">
|
||||
{{text-field tabindex="4" type="url" value=model.featuredLink id='topic-featured-link' placeholderKey="composer.topic_featured_link_placeholder"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{plugin-outlet "composer-fields"}}
|
||||
|
|
|
@ -25,9 +25,6 @@
|
|||
{{category-chooser valueAttribute="id" value=buffered.category_id}}
|
||||
{{/if}}
|
||||
|
||||
{{#if canEditTopicFeaturedLink}}
|
||||
{{text-field type="url" value=buffered.featured_link id='topic-featured-link' placeholderKey="composer.topic_featured_link_placeholder"}}
|
||||
{{/if}}
|
||||
{{#if canEditTags}}
|
||||
<br>
|
||||
{{tag-chooser tags=buffered.tags categoryId=buffered.category_id}}
|
||||
|
|
|
@ -1072,6 +1072,7 @@ en:
|
|||
|
||||
users_placeholder: "Add a user"
|
||||
title_placeholder: "What is this discussion about in one brief sentence?"
|
||||
title_or_link_placeholder: "Type title, or paste a link here"
|
||||
edit_reason_placeholder: "why are you editing?"
|
||||
show_edit_reason: "(add edit reason)"
|
||||
topic_featured_link_placeholder: "Enter link shown with title."
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import { acceptance } from "helpers/qunit-helpers";
|
||||
|
||||
acceptance("Composer topic featured links", {
|
||||
loggedIn: true,
|
||||
settings: {
|
||||
topic_featured_link_enabled: true
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("onebox with title", () => {
|
||||
visit("/");
|
||||
click('#create-topic');
|
||||
fillIn('#reply-title', "http://www.example.com/has-title.html");
|
||||
andThen(() => {
|
||||
ok(find('.d-editor-preview').html().trim().indexOf('onebox') > 0, "it pastes the link into the body and previews it");
|
||||
ok(exists('.d-editor-textarea-wrapper .popup-tip.good'), 'the body is now good');
|
||||
equal(find('.title-input input').val(), "An interesting article", "title is from the oneboxed article");
|
||||
});
|
||||
});
|
||||
|
||||
test("onebox result doesn't include a title", () => {
|
||||
visit("/");
|
||||
click('#create-topic');
|
||||
fillIn('#reply-title', 'http://www.example.com/no-title.html');
|
||||
andThen(() => {
|
||||
ok(find('.d-editor-preview').html().trim().indexOf('onebox') > 0, "it pastes the link into the body and previews it");
|
||||
ok(exists('.d-editor-textarea-wrapper .popup-tip.good'), 'the body is now good');
|
||||
equal(find('.title-input input').val(), "no-title.html", "title is from the end of the url");
|
||||
});
|
||||
});
|
||||
|
||||
test("no onebox result", () => {
|
||||
visit("/");
|
||||
click('#create-topic');
|
||||
fillIn('#reply-title', "http://www.example.com/nope-onebox.html");
|
||||
andThen(() => {
|
||||
equal(find('.d-editor-preview').html().trim().indexOf('onebox'), -1, "link isn't put into the post");
|
||||
equal(find('.d-editor-input').val().length, 0, "link isn't put into the post");
|
||||
equal(find('.title-input input').val(), "http://www.example.com/nope-onebox.html", "title is unchanged");
|
||||
});
|
||||
});
|
|
@ -320,6 +320,26 @@ export default function() {
|
|||
this.delete('/admin/users/:user_id/revoke_api_key', success);
|
||||
this.post('/admin/badges', success);
|
||||
this.delete('/admin/badges/:id', success);
|
||||
|
||||
this.get('/onebox', request => {
|
||||
if (request.queryParams.url === 'http://www.example.com/has-title.html') {
|
||||
return [
|
||||
200,
|
||||
{"Content-Type": "application/html"},
|
||||
'<aside class="onebox"><article class="onebox-body"><h3><a href="http://www.example.com/article.html">An interesting article</a></h3></article></aside>'
|
||||
];
|
||||
}
|
||||
|
||||
if (request.queryParams.url === 'http://www.example.com/no-title.html') {
|
||||
return [
|
||||
200,
|
||||
{"Content-Type": "application/html"},
|
||||
'<aside class="onebox"><article class="onebox-body"><p>No title</p></article></aside>'
|
||||
];
|
||||
}
|
||||
|
||||
return [404, {"Content-Type": "application/html"}, ''];;
|
||||
});
|
||||
});
|
||||
|
||||
server.prepareBody = function(body){
|
||||
|
|
|
@ -231,3 +231,19 @@ test("Title length for static page topics as admin", function() {
|
|||
composer.set('title', '');
|
||||
ok(!composer.get('titleLengthValid'), "admins must set title to at least 1 character");
|
||||
});
|
||||
|
||||
test("title placeholder depends on what you're doing", function() {
|
||||
let composer = createComposer({action: Composer.CREATE_TOPIC});
|
||||
equal(composer.get('titlePlaceholder'), 'composer.title_placeholder', "placeholder for normal topic");
|
||||
|
||||
composer = createComposer({action: Composer.PRIVATE_MESSAGE});
|
||||
equal(composer.get('titlePlaceholder'), 'composer.title_placeholder', "placeholder for private message");
|
||||
|
||||
Discourse.SiteSettings.topic_featured_link_enabled = true;
|
||||
|
||||
composer = createComposer({action: Composer.CREATE_TOPIC});
|
||||
equal(composer.get('titlePlaceholder'), 'composer.title_or_link_placeholder', "placeholder invites you to paste a link");
|
||||
|
||||
composer = createComposer({action: Composer.PRIVATE_MESSAGE});
|
||||
equal(composer.get('titlePlaceholder'), 'composer.title_placeholder', "placeholder for private message with topic links enabled");
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue