Can edit settings on the embedding page

This commit is contained in:
Robin Ward 2015-08-20 13:43:12 -04:00
parent d1c69189f3
commit 146f2eab7f
12 changed files with 277 additions and 30 deletions

View file

@ -0,0 +1,23 @@
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
classNames: ['embed-setting'],
@computed('field')
inputId(field) { return field.dasherize(); },
@computed('field')
translationKey(field) { return `admin.embedding.${field}`; },
@computed('type')
isCheckbox(type) { return type === "checkbox"; },
@computed('value')
checked: {
get(value) { return !!value; },
set(value) {
this.set('value', value);
return value;
}
}
});

View file

@ -0,0 +1,12 @@
import { on, observes } from 'ember-addons/ember-computed-decorators';
import highlightSyntax from 'discourse/lib/highlight-syntax';
export default Ember.Component.extend({
@on('didInsertElement')
@observes('code')
_refresh: function() {
highlightSyntax(this.$());
}
});

View file

@ -1,9 +1,46 @@
import computed from 'ember-addons/ember-computed-decorators';
import { popupAjaxError } from 'discourse/lib/ajax-error';
export default Ember.Controller.extend({ export default Ember.Controller.extend({
saved: false,
embedding: null, embedding: null,
// show settings if we have at least one created host
@computed('embedding.embeddable_hosts.@each.isCreated')
showSecondary() {
const hosts = this.get('embedding.embeddable_hosts');
return hosts.length && hosts.findProperty('isCreated');
},
@computed('embedding.base_url')
embeddingCode(baseUrl) {
const html =
`<div id='discourse-comments'></div>
<script type="text/javascript">
DiscourseEmbed = { discourseUrl: '${baseUrl}/',
discourseEmbedUrl: 'REPLACE_ME' };
(function() {
var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
})();
</script>`;
return html;
},
actions: { actions: {
saveChanges() { saveChanges() {
this.get('embedding').update({}); const embedding = this.get('embedding');
const updates = embedding.getProperties(embedding.get('fields'));
this.set('saved', false);
this.get('embedding').update(updates).then(() => {
this.set('saved', true);
}).catch(popupAjaxError);
}, },
addHost() { addHost() {

View file

@ -0,0 +1,11 @@
{{#if isCheckbox}}
<label for={{inputId}}>
{{input checked=checked id=inputId type="checkbox"}}
{{i18n translationKey}}
</label>
{{else}}
<label for={{inputId}}>{{i18n translationKey}}</label>
{{input value=value id=inputId}}
{{/if}}
<div class='clearfix'></div>

View file

@ -0,0 +1 @@
<pre><code class={{lang}}>{{code}}</code></pre>

View file

@ -1,15 +1,61 @@
{{#if embedding.embeddable_hosts}} <div class='embeddable-hosts'>
<table> {{#if embedding.embeddable_hosts}}
<tr> <table class='embedding'>
<th style='width: 50%'>{{i18n "admin.embedding.host"}}</th> <tr>
<th style='width: 30%'>{{i18n "admin.embedding.category"}}</th> <th style='width: 50%'>{{i18n "admin.embedding.host"}}</th>
<th style='width: 20%'>&nbsp;</th> <th style='width: 30%'>{{i18n "admin.embedding.category"}}</th>
</tr> <th style='width: 20%'>&nbsp;</th>
{{#each embedding.embeddable_hosts as |host|}} </tr>
{{embeddable-host host=host deleteHost="deleteHost"}} {{#each embedding.embeddable_hosts as |host|}}
{{/each}} {{embeddable-host host=host deleteHost="deleteHost"}}
</table> {{/each}}
</table>
{{else}}
<p>{{i18n "admin.embedding.get_started"}}</p>
{{/if}}
{{d-button label="admin.embedding.add_host" action="addHost" icon="plus" class="btn-primary add-host"}}
</div>
{{#if showSecondary}}
<div class='embedding-secondary'>
<p>{{{i18n "admin.embedding.sample"}}}</p>
{{highlighted-code code=embeddingCode lang="html"}}
</div>
<hr>
<div class='embedding-secondary'>
<h3>{{i18n "admin.embedding.settings"}}</h3>
{{embedding-setting field="embed_by_username" value=embedding.embed_by_username}}
{{embedding-setting field="embed_post_limit" value=embedding.embed_post_limit}}
{{embedding-setting field="embed_truncate" value=embedding.embed_truncate type="checkbox"}}
</div>
<div class='embedding-secondary'>
<h3>{{i18n "admin.embedding.feed_settings"}}</h3>
<p class="description">{{i18n "admin.embedding.feed_description"}}</p>
{{embedding-setting field="feed_polling_enabled" value=embedding.feed_polling_enabled type="checkbox"}}
{{embedding-setting field="feed_polling_url" value=embedding.feed_polling_url}}
{{embedding-setting field="embed_username_key_from_feed" value=embedding.embed_username_key_from_feed}}
</div>
<div class='embedding-secondary'>
<h3>{{i18n "admin.embedding.crawling_settings"}}</h3>
<p class="description">{{i18n "admin.embedding.crawling_description"}}</p>
{{embedding-setting field="embed_whitelist_selector" value=embedding.embed_whitelist_selector}}
{{embedding-setting field="embed_blacklist_selector" value=embedding.embed_blacklist_selector}}
</div>
<div class='embedding-secondary'>
{{d-button label="admin.embedding.save"
action="saveChanges"
class="btn-primary embed-save"
disabled=embedding.isSaving}}
{{#if saved}}{{i18n "saved"}}{{/if}}
</div>
{{/if}} {{/if}}
{{d-button label="admin.embedding.add_host" action="addHost" icon="plus" class="btn-primary"}}

View file

@ -1648,6 +1648,36 @@ table#user-badges {
margin-bottom: 10px; margin-bottom: 10px;
} }
// embedding
.embeddable-hosts {
table {
margin-bottom: 1em;
}
margin-bottom: 2em;
}
.embedding-secondary {
h3 {
margin: 1em 0;
}
margin-bottom: 2em;
.embed-setting {
input[type=text] {
width: 50%;
}
margin: 0.75em 0;
}
p.description {
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
margin-bottom: 1em;
max-width: 700px;
}
}
// Mobile specific styles // Mobile specific styles
// Mobile view text-inputs need some padding // Mobile view text-inputs need some padding
.mobile-view .admin-contents { .mobile-view .admin-contents {

View file

@ -1,3 +1,5 @@
require_dependency 'embedding'
class Admin::EmbeddingController < Admin::AdminController class Admin::EmbeddingController < Admin::AdminController
before_filter :ensure_logged_in, :ensure_staff, :fetch_embedding before_filter :ensure_logged_in, :ensure_staff, :fetch_embedding
@ -7,15 +9,21 @@ class Admin::EmbeddingController < Admin::AdminController
end end
def update def update
render_serialized(@embedding, EmbeddingSerializer, root: 'embedding', rest_serializer: true) Embedding.settings.each do |s|
@embedding.send("#{s}=", params[:embedding][s])
end
if @embedding.save
fetch_embedding
render_serialized(@embedding, EmbeddingSerializer, root: 'embedding', rest_serializer: true)
else
render_json_error(@embedding)
end
end end
protected protected
def fetch_embedding def fetch_embedding
@embedding = OpenStruct.new({ @embedding = Embedding.find
id: 'default',
embeddable_hosts: EmbeddableHost.all.order(:host)
})
end end
end end

41
app/models/embedding.rb Normal file
View file

@ -0,0 +1,41 @@
require 'has_errors'
class Embedding < OpenStruct
include HasErrors
def self.settings
%i(embed_by_username
embed_post_limit
embed_truncate
embed_whitelist_selector
embed_blacklist_selector
feed_polling_enabled
feed_polling_url
embed_username_key_from_feed)
end
def base_url
Discourse.base_url
end
def save
Embedding.settings.each do |s|
SiteSetting.send("#{s}=", send(s))
end
true
rescue Discourse::InvalidParameters => p
errors.add :base, p.to_s
false
end
def embeddable_hosts
EmbeddableHost.all.order(:host)
end
def self.find
embedding_args = { id: 'default' }
Embedding.settings.each {|s| embedding_args[s] = SiteSetting.send(s) }
Embedding.new(embedding_args)
end
end

View file

@ -1,8 +1,14 @@
class EmbeddingSerializer < ApplicationSerializer class EmbeddingSerializer < ApplicationSerializer
attributes :id attributes :id, :fields, :base_url
attributes *Embedding.settings
has_many :embeddable_hosts, serializer: EmbeddableHostSerializer, embed: :ids has_many :embeddable_hosts, serializer: EmbeddableHostSerializer, embed: :ids
def id def fields
object.id Embedding.settings
end
def read_attribute_for_serialization(attr)
object.respond_to?(attr) ? object.send(attr) : send(attr)
end end
end end

View file

@ -2492,12 +2492,29 @@ en:
delete_confirm: "Are you sure you want to delete the :%{name}: emoji?" delete_confirm: "Are you sure you want to delete the :%{name}: emoji?"
embedding: embedding:
get_started: "If you'd like to embed Discourse on another website, begin by adding its host."
confirm_delete: "Are you sure you want to delete that host?" confirm_delete: "Are you sure you want to delete that host?"
sample: "Use the following HTML code into your site to create and embed discourse topics. Replace <b>REPLACE_ME</b> with the canonical URL of the page you are embedding it on."
title: "Embedding" title: "Embedding"
host: "Allowed Hosts" host: "Allowed Hosts"
edit: "edit" edit: "edit"
category: "Post to Category" category: "Post to Category"
add_host: "Add Host" add_host: "Add Host"
settings: "Embedding Settings"
feed_settings: "Feed Settings"
feed_description: "Providing an RSS/ATOM feed for your site can improve Discourse's ability to import your content."
crawling_settings: "Crawler Settings"
crawling_description: "When Discourse creates topics for your posts, if no RSS/ATOM feed is present it will attempt to parse your content out of your HTML. Sometimes it can be challenging to extract your content, so we provide the ability to specify CSS rules to make extraction easier."
embed_by_username: "Username for topic creation"
embed_post_limit: "Maximum number of posts to embed"
embed_username_key_from_feed: "Key to pull discourse username from feed"
embed_truncate: "Truncate the embedded posts"
embed_whitelist_selector: "CSS selector for elements that are allowed in embeds"
embed_blacklist_selector: "CSS selector for elements that are removed from embeds"
feed_polling_enabled: "Import posts via RSS/ATOM"
feed_polling_url: "URL of RSS/ATOM feed to crawl"
save: "Save Embedding Settings"
permalink: permalink:
title: "Permalinks" title: "Permalinks"

View file

@ -759,16 +759,31 @@ developer:
default: false default: false
embedding: embedding:
feed_polling_enabled: false feed_polling_enabled:
feed_polling_url: '' default: false
hidden: true
feed_polling_url:
default: ''
hidden: true
embed_by_username: embed_by_username:
default: '' default: ''
type: username type: username
embed_username_key_from_feed: '' hidden: true
embed_post_limit: 100 embed_username_key_from_feed:
embed_truncate: false default: ''
embed_whitelist_selector: '' hidden: true
embed_blacklist_selector: '' embed_post_limit:
default: 100
hidden: true
embed_truncate:
default: false
hidden: true
embed_whitelist_selector:
default: ''
hidden: true
embed_blacklist_selector:
default: ''
hidden: true
legal: legal:
tos_url: tos_url: