Merge pull request #7256 from opf/fix/30096-Can-set-white-color-for-types-not-visible

[30096] Bright colours for WP Types cannot be seen

[ci skip]
pull/7269/head
Oliver Günther 6 years ago committed by GitHub
commit faa81db3cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      app/helpers/colors_helper.rb
  2. 7
      app/models/color.rb
  3. 23
      app/views/colors/_color_autocomplete_field.html.erb
  4. 2
      app/views/enumerations/_form.html.erb
  5. 1
      app/views/highlighting/styles.css.erb
  6. 2
      app/views/statuses/_form.html.erb
  7. 3
      app/views/types/form/_settings.html.erb
  8. 2
      config/locales/en.yml
  9. 1
      config/locales/js-en.yml
  10. 8
      frontend/src/app/components/wp-fast-table/builders/highlighting/highlighting.functions.ts
  11. 111
      frontend/src/app/modules/common/colors/colors-autocompleter.component.ts

@ -29,10 +29,13 @@
#++
module ColorsHelper
def options_for_colors(colored_thing, default_label: I18n.t('colors.label_no_color'), default_color: '')
s = content_tag(:option, default_label, value: default_color)
def options_for_colors(colored_thing, allow_bright_colors)
colors = []
Color.find_each do |c|
next if !allow_bright_colors && c.super_bright?
options = {}
options[:name] = c.name
options[:value] = c.id
options[:data] = {
color: c.hexcode,
@ -41,9 +44,13 @@ module ColorsHelper
}
options[:selected] = true if c.id == colored_thing.color_id
s << content_tag(:option, c.name, options)
colors.push(options)
end
s
colors.to_json
end
def selected_color(colored_thing)
colored_thing.color_id
end
def darken_color(hex_color, amount = 0.4)
@ -61,6 +68,21 @@ module ColorsHelper
content_tag(:span, color.hexcode, class: 'color--text-preview', style: style)
end
#
# Styles to display colors itself (e.g. for the colors autocompleter)
##
def color_css
Color.find_each do |color|
concat ".__hl_inline_color_#{color.id}_dot::before { background-color: #{color.hexcode} !important;}"
concat ".__hl_inline_color_#{color.id}_dot::before { border: 1px solid #555555 !important;}" if color.bright?
concat ".__hl_inline_color_#{color.id}_text { color: #{color.hexcode} !important;}"
concat ".__hl_inline_color_#{color.id}_text { -webkit-text-stroke: 0.5px grey; text-stroke: 0.5px grey;}" if color.super_bright?
end
end
#
# Styles to display the color of attributes (type, status etc.) for example in the WP view
##
def resource_color_css(name, scope)
scope.includes(:color).find_each do |entry|
color = entry.color
@ -77,6 +99,7 @@ module ColorsHelper
if name === 'type'
concat ".__hl_inline_#{name}_#{entry.id} { color: #{color.hexcode} !important;}"
concat ".__hl_inline_#{name}_#{entry.id} { -webkit-text-stroke: 0.5px grey;}" if color.super_bright?
else
concat ".__hl_inline_#{name}_#{entry.id}::before { #{background_style}; border-color: #{border_color}; }\n"
end

@ -71,6 +71,13 @@ class Color < ActiveRecord::Base
brightness_yiq >= 128
end
##
# Returns whether the color is very bright according to
# YIQ lightness.
def super_bright?
brightness_yiq >= 200
end
##
# Sum the color values of each channel
# Same as in frontend color-contrast.functions.ts

@ -1,12 +1,19 @@
<% form_field_class = form_field_class || '' %>
<% container_class = container_class || '' %>
<div class="form--field <%= form_field_class %>">
<%= form.select :color_id,
options_for_colors(object),
{},
container_class: container_class.present? ? container_class : '-middle',
class: 'colors-autocomplete' %>
<% highlight_text_inline = highlight_text_inline || false %>
<div class="form--field <%= form_field_class %>"<%= %>>
<label class="form--label">
<%= t('activerecord.attributes.color') %>
</label>
<div class="form--field-container">
<%= form.hidden_field :color_id %>
<%= content_tag('colors-autocompleter',
'',
class: "colors-autocomplete form--select-container " + "#{container_class.present? ? container_class : '-middle'}",
data: { colors: options_for_colors(object, allow_bright_colors),
selected_color: selected_color(object),
highlight_text_inline: highlight_text_inline,
update_input: type + '[color_id]'}) %>
</div>
<div class="form--field-instructions"><%= label %></div>
<colors-autocompleter></colors-autocompleter>
</div>

@ -44,6 +44,8 @@ See docs/COPYRIGHT.rdoc for more details.
locals: {
form: f,
object: @enumeration,
type: 'enumeration',
allow_bright_colors: true,
label: @enumeration.color_label
} %>
<% end %>

@ -2,6 +2,7 @@
<%= resource_color_css('status', ::Status) %>
<%= resource_color_css('priority', ::IssuePriority) %>
<%= resource_color_css('type', ::Type) %>
<%= color_css() %>
<%# Overdue tasks %>
.__hl_date_due_today { color: #F76707 !important; }

@ -57,6 +57,8 @@ See docs/COPYRIGHT.rdoc for more details.
locals: {
form: f,
object: @status,
type: 'status',
allow_bright_colors: true,
label: t('statuses.edit.status_color_text')
} %>

@ -36,6 +36,9 @@ See docs/COPYRIGHT.rdoc for more details.
locals: {
form: f,
object: @type,
type: 'type',
allow_bright_colors: false,
highlight_text_inline: true,
label: t('types.edit.type_color_text'),
form_field_class: '-wide-label',
container_class: '-slim'

@ -252,7 +252,7 @@ en:
reset: "Reset to defaults"
type_color_text: |
Click to assign or change the color of this type. The selected color distinguishes work packages
in Gantt charts.
in Gantt charts. It is therefore recommended to use a strong color.
versions:
overview:

@ -285,6 +285,7 @@ en:
label_more_than_ago: "more than days ago"
label_my_page: "My page"
label_next: "Next"
label_no_color: "No color"
label_no_data: "No data to display"
label_no_due_date: "no end date"
label_no_start_date: "no start date"

@ -7,6 +7,14 @@ export namespace Highlighting {
return `__hl_inline_${property}_${id}`;
}
export function colorClass(highlightColorTextInline:boolean, id:string|number) {
if (highlightColorTextInline) {
return `__hl_inline_color_${id}_text`;
} else {
return `__hl_inline_color_${id}_dot`;
}
}
/**
* Given the difference from today (negative = n days in the past),
* output the fixed overdue classes

@ -28,73 +28,84 @@
import {Component, ElementRef, OnInit} from '@angular/core';
import {DynamicBootstrapper} from "core-app/globals/dynamic-bootstrapper";
export const selector = 'colors-autocompleter';
import {Highlighting} from "core-components/wp-fast-table/builders/highlighting/highlighting.functions";
import {DynamicCssService} from "core-app/modules/common/dynamic-css/dynamic-css.service";
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
@Component({
selector: selector,
template: '',
template: `
<ng-select [items]="options"
[virtualScroll]="true"
bindLabel="name"
bindValue="value"
[(ngModel)]="selectedOption"
(change)="onModelChange($event)"
[clearable]="false"
appendTo="body">
<ng-template ng-label-tmp let-item="item">
<span [ngClass]="highlightColor(item)">{{item.name}}</span>
</ng-template>
<ng-template ng-option-tmp let-item="item" let-index="index">
<span [ngClass]="highlightColor(item)">{{item.name}}</span>
</ng-template>
</ng-select>
`,
selector: 'colors-autocompleter'
})
export class ColorsAutocompleter implements OnInit {
private $element:JQuery;
private $select:JQuery;
constructor(private readonly elementRef:ElementRef) {
public options:any[];
public selectedOption:any;
private highlightTextInline:boolean = false;
private updateInputField:HTMLInputElement|undefined;
private selectedColorId:string;
constructor(protected elementRef:ElementRef,
protected readonly I18n:I18nService,
protected readonly dynamicCssService:DynamicCssService) {
}
ngOnInit() {
this.$element = jQuery(this.elementRef.nativeElement);
this.$select = jQuery(this.$element.parent().find('select.colors-autocomplete'));
this.dynamicCssService.requireHighlighting();
this.setColorOptions();
this.$select.removeClass('form--select');
this.setupSelect2();
this.updateInputField = document.getElementsByName(this.elementRef.nativeElement.dataset.updateInput)[0] as HTMLInputElement|undefined;
this.highlightTextInline = JSON.parse(this.elementRef.nativeElement.dataset.highlightTextInline);
}
protected formatter(state:any) {
const item:JQuery = jQuery(state.element);
const color = item.data('color');
const contrastingColor = item.data('background');
const bright = item.data('bright');
// Special case, no color
if (!color) {
const div = jQuery('<div>')
.append(item.text())
.addClass('ui-menu-item-wrapper');
return div;
public onModelChange(color:any) {
if (color && this.updateInputField) {
this.updateInputField.value = color.value;
}
}
const colorSquare = jQuery('<span>')
.addClass('color--preview')
.css('background-color', color);
const colorText = jQuery('<span>')
.addClass('color--text-preview')
.css('color', bright ? '#333333' : '#FFFFFF')
.css('background-color', color)
.text(item.text());
private setColorOptions() {
this.options = JSON.parse(this.elementRef.nativeElement.dataset.colors);
this.options.unshift({name: this.I18n.t('js.label_no_color'), value: ''});
const div = jQuery('<div>')
.append(colorSquare)
.append(colorText)
.addClass('ui-menu-item-wrapper');
this.selectedOption = this.options.find((item) => item.selected === true);
return div;
if (this.selectedOption) {
this.selectedOption = this.selectedOption.value;
} else {
// Differentiate between "No color" and a color that is now not selectable any more
this.selectedColorId = this.elementRef.nativeElement.dataset.selectedColor;
this.selectedOption = this.selectedColorId ? this.selectedColorId : '';
}
}
protected setupSelect2() {
this.$select.select2({
formatResult: this.formatter,
formatSelection: this.formatter,
escapeMarkup: (m:any) => m
});
private highlightColor(item:any) {
if (item.value === '') { return; }
let highlightingClass;
if (this.highlightTextInline) {
highlightingClass = '__hl_inline_type_ ';
} else {
highlightingClass = '__hl_inline_ ';
}
return highlightingClass + Highlighting.colorClass(this.highlightTextInline, item.value);
}
}
DynamicBootstrapper.register({
selector: selector,
cls: ColorsAutocompleter
});
DynamicBootstrapper.register({ selector: 'colors-autocompleter', cls: ColorsAutocompleter });

Loading…
Cancel
Save