Merge pull request #3965 from tgxworld/decorate_category_hashtag

Decorate category hashtag
This commit is contained in:
Guo Xiang Tan 2016-01-19 11:49:32 +08:00
commit c2c1aea381
9 changed files with 147 additions and 43 deletions

View File

@ -3,6 +3,7 @@ import loadScript from 'discourse/lib/load-script';
import { default as computed, on, observes } from 'ember-addons/ember-computed-decorators';
import { showSelector } from "discourse/lib/emoji/emoji-toolbar";
import Category from 'discourse/models/category';
import { SEPARATOR as categoryHashtagSeparator } from 'discourse/lib/category-hashtags';
// Our head can be a static string or a function that returns a string
// based on input (like for numbered lists).
@ -255,7 +256,7 @@ export default Ember.Component.extend({
template: template,
key: '#',
transformComplete(category) {
return Category.slugFor(category, ":");
return Category.slugFor(category, categoryHashtagSeparator);
},
dataSource(term) {
return Category.search(term);

View File

@ -21,7 +21,7 @@ export function categoryBadgeHTML(category, opts) {
var description = get(category, 'description_text'),
restricted = get(category, 'read_restricted'),
url = Discourse.getURL("/c/") + Discourse.Category.slugFor(category),
url = opts.url ? opts.url : Discourse.getURL("/c/") + Discourse.Category.slugFor(category),
href = (opts.link === false ? '' : url),
tagName = (opts.link === false || opts.link === "false" ? 'span' : 'a'),
extraClasses = (opts.extraClasses ? (' ' + opts.extraClasses) : ''),

View File

@ -0,0 +1,26 @@
import Category from 'discourse/models/category';
import { categoryBadgeHTML } from 'discourse/helpers/category-link';
export const SEPARATOR = ":";
export function findCategoryByHashtagSlug(hashtagSlug) {
if (hashtagSlug.indexOf('#') === 0) hashtagSlug = hashtagSlug.slice(1);
return Category.findBySlug.apply(null, hashtagSlug.split(SEPARATOR, 2).reverse());
};
export function replaceSpan($elem, categorySlug, categoryLink) {
const category = findCategoryByHashtagSlug(categorySlug);
if (!category) {
$elem.replaceWith(categorySlug);
} else {
$elem.replaceWith(categoryBadgeHTML(
category, { url: categoryLink, allowUncategorized: true }
));
}
};
export function decorateLinks($elems) {
$elems.each((_, elem) => replaceSpan($(elem), elem.text, elem.href));
}

View File

@ -1,12 +1,10 @@
import { replaceSpan } from 'discourse/lib/category-hashtags';
const validCategoryHashtags = {};
const checkedCategoryHashtags = [];
const testedKey = 'tested';
const testedClass = `hashtag-${testedKey}`;
function replaceSpan($elem, categorySlug, categoryLink) {
$elem.replaceWith(`<a href="${categoryLink}" class="hashtag">#${categorySlug}</a>`);
}
function updateFound($hashtags, categorySlugs) {
Ember.run.schedule('afterRender', () => {
$hashtags.each((index, hashtag) => {

View File

@ -3,6 +3,7 @@ import { number } from 'discourse/lib/formatter';
import DiscourseURL from 'discourse/lib/url';
import { default as computed, on } from 'ember-addons/ember-computed-decorators';
import { fmt } from 'discourse/lib/computed';
import { decorateLinks as decorateCategoryHashtagLinks } from 'discourse/lib/category-hashtags';
const DAY = 60 * 50 * 1000;
@ -75,6 +76,7 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
_cookedWasChanged() {
this.trigger('postViewUpdated', this.$());
this._insertQuoteControls();
this._decorateCategoryHashtagLinks();
},
mouseUp(e) {
@ -318,6 +320,7 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
const $post = this.$(),
postNumber = this.get('post').get('post_number');
this._decorateCategoryHashtagLinks();
this._showLinkCounts();
ScreenTrack.current().track($post.prop('id'), postNumber);
@ -375,7 +378,12 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
cooked.unhighlight();
this._highlighted = false;
}
}.observes('searchService.highlightTerm', 'cooked')
}.observes('searchService.highlightTerm', 'cooked'),
_decorateCategoryHashtagLinks() {
const $elems = this.$('.cooked a.hashtag');
if ($elems.length > 0) decorateCategoryHashtagLinks($elems);
}
});
export default PostView;

View File

@ -30,7 +30,7 @@
color: $primary !important;
padding: 3px;
vertical-align: text-top;
margin-top: -3px; //vertical alignment fix
margin-top: -2px; //vertical alignment fix
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
@ -38,21 +38,18 @@
.extra-info-wrapper & {
color: $header-primary !important;
}
}
}
.badge-category-parent-bg, .badge-category-bg {
display: inline-block;
padding: 1px;
&:before {
content: "\a0";
}
}
.badge-category-parent-bg, .badge-category-bg {
display: inline-block;
padding: 1px;
&:before {
content: "\a0";
}
}
}
&.bullet { //bullet category style
display: inline-flex;
align-items: baseline;
@ -71,31 +68,30 @@
.extra-info-wrapper & {
color: $header-primary !important;
}
}
}
.badge-category-parent-bg, .badge-category-bg {
width: 10px;
height: 10px;
margin-right: 5px;
display: inline-block;
line-height: 1;
width: 10px;
height: 10px;
margin-right: 5px;
display: inline-block;
line-height: 1;
&:before {
content: "\a0";
}
}
&:before {
content: "\a0";
}
}
span {
&.badge-category-parent-bg { //subcategory style
width: 5px;
margin-right: 0;
& + .badge-category-bg {
width: 5px;
}
}
}
}
span {
&.badge-category-parent-bg { //subcategory style
width: 5px;
margin-right: 0;
& + .badge-category-bg {
width: 5px;
}
}
}
}
&.box { //box category style (apply custom widths to the wrapper, not the children)
@ -134,6 +130,59 @@
}
}
@mixin cooked-badge-bullet($length, $offset:0px) {
.badge-wrapper.bullet {
span {
position: relative;
&.badge-category-bg {
width: $length;
height: $length;
top: $offset;
}
&.badge-category-parent-bg {
width: $length / 2;
height: $length;
top: $offset;
& + .badge-category-bg {
width: $length / 2;
}
}
}
}
}
.cooked, .d-editor-preview {
p .badge-wrapper.bullet {
margin: 0px 2.5px;
}
h1 { @include cooked-badge-bullet(22px) }
h2 { @include cooked-badge-bullet(17px) }
h3 { @include cooked-badge-bullet(14px) }
h4 { @include cooked-badge-bullet(12px) }
h5 { @include cooked-badge-bullet(10px, -1.1px) }
h6 { @include cooked-badge-bullet(9px, -1.5px) }
.badge-wrapper.box {
span {
display: inline;
}
.badge-notification.clicks {
display: inline-block;
overflow: visible;
top: 0px;
}
.badge-category-bg {
padding-right: 5px;
}
}
}
// Category badge dropdown
// --------------------------------------------------

View File

@ -5,7 +5,7 @@ module CategoryHashtag
class_methods do
def query_from_hashtag_slug(category_slug)
parent_slug, child_slug = category_slug.split(":", 2)
parent_slug, child_slug = category_slug.split(SEPARATOR, 2)
category = Category.where(slug: parent_slug, parent_category_id: nil)

View File

@ -11,7 +11,7 @@ describe CategoryHashtag do
end
it "should return the right result for a parent and child category slug" do
expect(Category.query_from_hashtag_slug("#{parent_category.slug}:#{child_category.slug}"))
expect(Category.query_from_hashtag_slug("#{parent_category.slug}#{CategoryHashtag::SEPARATOR}#{child_category.slug}"))
.to eq(child_category)
end
@ -20,7 +20,7 @@ describe CategoryHashtag do
end
it "should return nil for incorrect parent and child category slug" do
expect(Category.query_from_hashtag_slug("random-slug:random-slug")).to eq(nil)
expect(Category.query_from_hashtag_slug("random-slug#{CategoryHashtag::SEPARATOR}random-slug")).to eq(nil)
end
end
end

View File

@ -0,0 +1,22 @@
import createStore from 'helpers/create-store';
import Category from 'discourse/models/category';
import { findCategoryByHashtagSlug } from "discourse/lib/category-hashtags";
module("lib:category-hashtags");
test('findCategoryByHashtagSlug', () => {
const store = createStore();
const parentCategory = store.createRecord('category', { slug: 'test1' });
const childCategory = store.createRecord('category', {
slug: 'test2', parentCategory: parentCategory
});
sandbox.stub(Category, 'list').returns([parentCategory, childCategory]);
equal(findCategoryByHashtagSlug('test1'), parentCategory, 'returns the right category');
equal(findCategoryByHashtagSlug('test1:test2'), childCategory, 'returns the right category');
equal(findCategoryByHashtagSlug('#test1'), parentCategory, 'returns the right category');
equal(findCategoryByHashtagSlug('#test1:test2'), childCategory, 'returns the right category');
});