Skip to content

Commit

Permalink
implement color picking from predefined set for category badges + opt…
Browse files Browse the repository at this point in the history
…ion to change foreground color
  • Loading branch information
kubamracek committed Mar 14, 2013
1 parent a8c44d9 commit 8784c55
Show file tree
Hide file tree
Showing 17 changed files with 142 additions and 35 deletions.
5 changes: 3 additions & 2 deletions app/assets/javascripts/discourse/components/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ Discourse.Utilities = {

// Create a badge like category link
categoryLink: function(category) {
var color, name, description, result;
var color, textColor, name, description, result;
if (!category) return "";

color = Em.get(category, 'color');
textColor = Em.get(category, 'text_color');
name = Em.get(category, 'name');
description = Em.get(category, 'description');

Expand All @@ -52,7 +53,7 @@ Discourse.Utilities = {
// Add description if we have it
if (description) result += "title=\"" + description + "\" ";

return result + "style=\"background-color: #" + color + "\">" + name + "</a>";
return result + "style=\"background-color: #" + color + "; color: #" + textColor + ";\">" + name + "</a>";
},

avatarUrl: function(username, size, template) {
Expand Down
7 changes: 4 additions & 3 deletions app/assets/javascripts/discourse/models/category.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Discourse.Category = Discourse.Model.extend({
}).property('name'),

style: (function() {
return "background-color: #" + (this.get('color'));
}).property('color'),
return "background-color: #" + (this.get('category.color')) + "; color: #" + (this.get('category.text_color')) + ";";
}).property('color', 'text_color'),

moreTopics: (function() {
return this.get('topic_count') > Discourse.SiteSettings.category_featured_topics;
Expand All @@ -32,7 +32,8 @@ Discourse.Category = Discourse.Model.extend({
return this.ajax(url, {
data: {
name: this.get('name'),
color: this.get('color')
color: this.get('color'),
text_color: this.get('text_color')
},
type: this.get('id') ? 'PUT' : 'POST',
success: function(result) { return args.success(result); },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class='contents'>
<span class='badge-category' style='background-color: #{{unbound view.color}}'>{{unbound view.name}}</span>
<span class='badge-category' style='background-color: #{{unbound view.color}}; color: #{{unbound view.text_color}}'>{{unbound view.name}}</span>

{{#if view.excerpt}}
<div class='description'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,22 @@

</div>

<label>{{i18n category.color}}</label>
<label>{{i18n category.badge_colors}}</label>

<div class='input-prepend input-append'>
<span class='add-on'>#</span>{{view Discourse.TextField valueBinding="view.category.color" placeholderKey="category.color_placeholder" maxlength="6"}}
<span class='badge-category' {{bindAttr style="view.colorStyle"}}>{{i18n preview}}</span>
<div class="category-color-editor">
<span class='badge-category' {{bindAttr style="view.colorStyle"}}>{{i18n preview}}</span>

<div class='input-prepend input-append' style="margin-top: 10px;">
<span class='color-title'>{{i18n category.background_color}}:</span>
<span class='add-on'>#</span>{{view Discourse.TextField valueBinding="view.category.color" placeholderKey="category.color_placeholder" maxlength="6"}}
{{view Discourse.ColorsView colorsBinding="view.predefinedColors" valueBinding="view.category.color"}}
</div>

<div class='input-prepend input-append'>
<span class='color-title'>{{i18n category.foreground_color}}:</span>
<span class='add-on'>#</span>{{view Discourse.TextField valueBinding="view.category.text_color" placeholderKey="category.color_placeholder" maxlength="6"}}
{{view Discourse.ColorsView colorsBinding="view.predefinedColors" valueBinding="view.category.text_color"}}
</div>
</div>

</form>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{#with view.content}}
<a href='{{unbound url}}'>
<span class='badge-category' style="background-color: #{{unbound color}}">{{unbound title}}</span>
<span class='badge-category' style="background-color: #{{unbound color}}; color: #{{unbound text_color}};">{{unbound title}}</span>
</a>
{{/with}}

Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
**/
Discourse.ComboboxViewCategory = Discourse.ComboboxView.extend({
none: 'category.none',
dataAttributes: ['color', 'description'],
dataAttributes: ['color', 'text_color', 'description'],

template: function(text, templateData) {
if (!templateData.color) return text;

var result = "<span class='badge-category' style='background-color: #" + templateData.color + "' "
var result = "<span class='badge-category' style='background-color: #" + templateData.color + '; color: #' +
templateData.text_color + ";' ";
if (templateData.description && templateData.description !== 'null') {
result += "title=\"" + templateData.description + "\" ";
}
Expand Down
34 changes: 34 additions & 0 deletions app/assets/javascripts/discourse/views/modal/colors_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
This view shows an array of buttons for selection of a color from a predefined set.
@class ColorsView
@extends Ember.ContainerView
@namespace Discourse
@module Discourse
**/
Discourse.ColorsView = Ember.ContainerView.extend({
classNames: 'colors-container',

init: function() {
this._super();
return this.createButtons();
},

createButtons: function() {
var colors = this.get('colors');
var _this = this;

colors.each(function(color) {
_this.addObject(Discourse.View.create({
tagName: 'button',
attributeBindings: ['style'],
classNames: ['colorpicker'],
style: 'background-color: #' + color + ';',
click: function() {
_this.set("value", color);
return false;
}
}));
});
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ Discourse.EditCategoryView = Discourse.ModalBodyView.extend({
}).property('category.name', 'category.color'),

colorStyle: (function() {
return "background-color: #" + (this.get('category.color')) + ";";
}).property('category.color'),
return "background-color: #" + (this.get('category.color')) + "; color: #" + (this.get('category.text_color')) + ";";
}).property('category.color', 'category.text_color'),

predefinedColors: ["FFFFFF", "000000", "AECFC6", "836953", "77DD77", "FFB347", "FDFD96", "536878",
"EC5800", "0096E0", "7C4848", "9AC932", "BA160C", "003366", "B19CD9", "E4717A"],

title: (function() {
if (this.get('category.id')) return Em.String.i18n("category.edit_long");
Expand All @@ -36,7 +39,7 @@ Discourse.EditCategoryView = Discourse.ModalBodyView.extend({
if (this.get('category')) {
this.set('id', this.get('category.slug'));
} else {
this.set('category', Discourse.Category.create({ color: 'AB9364' }));
this.set('category', Discourse.Category.create({ color: 'AB9364', text_color: 'FFFFFF' }));
}
},

Expand Down
29 changes: 29 additions & 0 deletions app/assets/stylesheets/application/colorpicker.css.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// styles for the category badge color picker

@import "foundation/variables";
@import "foundation/mixins";

.category-color-editor {
input {
width: 70px;
}

.color-title {
display: inline-block;
width: 130px;
}

.colors-container {
display: inline-block;
vertical-align: bottom;
padding-bottom: 2px;
padding-left: 15px;

.colorpicker {
border: 1px solid $darkish_gray;
width: 15px;
height: 15px;
margin-right: 2px;
}
}
}
2 changes: 1 addition & 1 deletion app/controllers/categories_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def destroy
private

def category_param_keys
[:name, :color]
[:name, :color, :text_color]
end

def category_params
Expand Down
2 changes: 1 addition & 1 deletion app/serializers/category_excerpt_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
class CategoryExcerptSerializer < ActiveModel::Serializer
include ExcerptType

attributes :excerpt, :name, :color, :slug, :topic_url, :topics_year,
attributes :excerpt, :name, :color, :text_color, :slug, :topic_url, :topics_year,
:topics_month, :topics_week, :category_url, :can_edit, :can_delete


Expand Down
1 change: 1 addition & 0 deletions app/serializers/category_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ class CategorySerializer < ApplicationSerializer
attributes :id,
:name,
:color,
:text_color,
:slug,
:topic_count,
:description,
Expand Down
4 changes: 3 additions & 1 deletion config/locales/client.cs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,9 @@ cs:
name: "Název kategorie"
description: "Popis"
topic: "téma kategorie"
color: "Barva"
badge_colors: "Barvy štítku"
background_color: "Barva pozadí"
foreground_color: "Barva textu"
name_placeholder: "Měl by být krátký a výstižný."
color_placeholder: "Jakákoliv webová barva"
delete_confirm: "Opravdu chcete odstranit tuto kategorii?"
Expand Down
4 changes: 3 additions & 1 deletion config/locales/client.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,9 @@ en:
name: "Category Name"
description: "Description"
topic: "category topic"
color: "Color"
badge_colors: "Badge colors"
background_color: "Background color"
foreground_color: "Foreground color"
name_placeholder: "Should be short and succinct."
color_placeholder: "Any web color"
delete_confirm: "Are you sure you want to delete that category?"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddForegroundColorToCategories < ActiveRecord::Migration
def change
add_column :categories, :text_color, :string, limit: 6, null: false, default: 'FFFFFF'
end
end
13 changes: 9 additions & 4 deletions lib/search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ def self.user_query_sql
'/users/' || u.username_lower AS url,
u.username AS title,
u.email,
NULL AS color
NULL AS color,
NULL AS text_color
FROM users AS u
JOIN users_search s on s.id = u.id
WHERE s.search_data @@ TO_TSQUERY(:locale, :query)
Expand All @@ -29,7 +30,8 @@ def self.topic_query_sql
'/t/slug/' || ft.id AS url,
ft.title,
NULL AS email,
NULL AS color
NULL AS color,
NULL AS text_color
FROM topics AS ft
JOIN posts AS p ON p.topic_id = ft.id AND p.post_number = 1
JOIN posts_search s on s.id = p.id
Expand All @@ -52,7 +54,8 @@ def self.post_query_sql
'/t/slug/' || ft.id || '/' || p.post_number AS url,
ft.title,
NULL AS email,
NULL AS color
NULL AS color,
NULL AS text_color
FROM topics AS ft
JOIN posts AS p ON p.topic_id = ft.id AND p.post_number <> 1
JOIN posts_search s on s.id = p.id
Expand All @@ -74,7 +77,8 @@ def self.category_query_sql
'/category/' || c.slug AS url,
c.name AS title,
NULL AS email,
c.color
c.color,
c.text_color
FROM categories AS c
JOIN categories_search s on s.id = c.id
WHERE s.search_data @@ TO_TSQUERY(:locale, :query)
Expand Down Expand Up @@ -168,6 +172,7 @@ def self.query(term, type_filter=nil, min_search_term_length=3)
end
row.delete('email')
row.delete('color') unless type == 'category'
row.delete('text_color') unless type == 'category'

grouped[type] ||= []
grouped[type] << row
Expand Down
34 changes: 23 additions & 11 deletions spec/controllers/categories_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,26 @@

it "raises an exception when they don't have permission to create it" do
Guardian.any_instance.expects(:can_create?).with(Category, nil).returns(false)
xhr :post, :create, name: 'hello', color: '#ff0'
xhr :post, :create, name: 'hello', color: 'ff0', text_color: 'fff'
response.should be_forbidden
end

it 'raises an exception when the name is missing' do
lambda { xhr :post, :create, color: '#ff0' }.should raise_error(Discourse::InvalidParameters)
lambda { xhr :post, :create, color: 'ff0', text_color: 'fff' }.should raise_error(Discourse::InvalidParameters)
end

it 'raises an exception when the color is missing' do
lambda { xhr :post, :create, name: 'hello' }.should raise_error(Discourse::InvalidParameters)
lambda { xhr :post, :create, name: 'hello', text_color: 'fff' }.should raise_error(Discourse::InvalidParameters)
end

it 'raises an exception when the text color is missing' do
lambda { xhr :post, :create, name: 'hello', color: 'ff0' }.should raise_error(Discourse::InvalidParameters)
end

describe 'failure' do
before do
@category = Fabricate(:category, user: @user)
xhr :post, :create, name: @category.name, color: '#ff0'
xhr :post, :create, name: @category.name, color: 'ff0', text_color: 'fff'
end

it { should_not respond_with(:success) }
Expand All @@ -42,7 +46,7 @@

describe 'success' do
before do
xhr :post, :create, name: 'hello', color: '#ff0'
xhr :post, :create, name: 'hello', color: 'ff0', text_color: 'fff'
end

it 'creates a category' do
Expand Down Expand Up @@ -97,22 +101,26 @@

it "raises an exception if they don't have permission to edit it" do
Guardian.any_instance.expects(:can_edit?).returns(false)
xhr :put, :update, id: @category.slug, name: 'hello', color: '#ff0'
xhr :put, :update, id: @category.slug, name: 'hello', color: 'ff0', text_color: 'fff'
response.should be_forbidden
end

it "requires a name" do
lambda { xhr :put, :update, id: @category.slug, color: '#fff' }.should raise_error(Discourse::InvalidParameters)
lambda { xhr :put, :update, id: @category.slug, color: 'fff', text_color: '0ff' }.should raise_error(Discourse::InvalidParameters)
end

it "requires a color" do
lambda { xhr :put, :update, id: @category.slug, name: 'asdf'}.should raise_error(Discourse::InvalidParameters)
lambda { xhr :put, :update, id: @category.slug, name: 'asdf', text_color: '0ff' }.should raise_error(Discourse::InvalidParameters)
end

it "requires a text color" do
lambda { xhr :put, :update, id: @category.slug, name: 'asdf', color: 'fff' }.should raise_error(Discourse::InvalidParameters)
end

describe 'failure' do
before do
@other_category = Fabricate(:category, name: 'Other', user: @user )
xhr :put, :update, id: @category.id, name: @other_category.name, color: '#ff0'
xhr :put, :update, id: @category.id, name: @other_category.name, color: 'ff0', text_color: 'fff'
end

it 'returns errors on a duplicate category name' do
Expand All @@ -126,7 +134,7 @@

describe 'success' do
before do
xhr :put, :update, id: @category.id, name: 'science', color: '#000'
xhr :put, :update, id: @category.id, name: 'science', color: '000', text_color: '0ff'
@category.reload
end

Expand All @@ -135,7 +143,11 @@
end

it 'updates the color' do
@category.color.should == '#000'
@category.color.should == '000'
end

it 'updates the text color' do
@category.text_color.should == '0ff'
end

end
Expand Down

0 comments on commit 8784c55

Please sign in to comment.