fix : keyboard accessibility for colorpicker inpus

This commit is contained in:
jdescottes 2015-02-12 00:39:38 +01:00
parent 334d6ad21f
commit 561d016a45
6 changed files with 171 additions and 90 deletions

View file

@ -66,7 +66,8 @@
display: none;
}
.color-picker-slider {
.color-picker-slider,
.color-picker-input {
padding: 0 10px;
height : 25px;
overflow: hidden;
@ -91,6 +92,14 @@
margin-left: 5px;
}
.color-picker-input {
margin-bottom: 10px;
}
.color-picker-input .textfield{
width:100%;
}
.color-picker-slider input[type="range"][data-dimension="h"] {
background-image:linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
}

View file

@ -60,7 +60,7 @@
.color-preview {
width: 170px;
height: 76px;
height: 70px;
margin: 11px;
}

View file

@ -46,3 +46,7 @@ body {
.pull-left {
left:0;
}
.uppercase {
text-transform: uppercase;
}

View file

@ -101,6 +101,10 @@ if (!Function.prototype.bind) {
return hash;
};
ns.copy = function (object) {
return JSON.parse(JSON.stringify(object));
};
var entityMap = {
"&": "&",
"<": "&lt;",

View file

@ -4,6 +4,11 @@
ns.HslRgbColorPicker = function (container, colorUpdatedCallback) {
this.container = container;
this.colorUpdatedCallback = colorUpdatedCallback;
this.tinyColor = null;
this.hsvColor = null;
this.rgbColor = null;
this.lastInputTimestamp_ = 0;
};
@ -12,16 +17,15 @@
var changeEvent = isChromeOrFirefox ? 'input' : 'change';
this.container.addEventListener(changeEvent, this.onPickerChange_.bind(this));
this.container.addEventListener('keydown', this.onKeydown_.bind(this));
this.container.addEventListener('focusout', this.onBlur_.bind(this));
this.spectrumEl = this.container.querySelector('.color-picker-spectrum');
$(this.spectrumEl).spectrum({
flat: true,
showInput: true,
showButtons: false,
move : this.setColor.bind(this),
change : this.setColor.bind(this),
preferredFormat: 'hex'
change : this.setColor.bind(this)
});
this.setColor("#000000");
@ -34,49 +38,72 @@
ns.HslRgbColorPicker.prototype.onPickerChange_ = function (evt) {
var target = evt.target;
if (target.dataset.dimension) {
var model = target.dataset.model;
var dimension = target.dataset.dimension;
var value = target.value;
var value = parseInt(target.value, 10);
if (dimension === 'v' || dimension === 's') {
value = value/100;
this.updateColor_(value, model, dimension);
}
var color;
if (model === 'rgb') {
color = this.tinyColor.toRgb();
} else if (model === 'hsv') {
color = this.hsvColor;
}
if (isNaN(value)) {
value = color[dimension];
} else {
color[dimension] = value;
}
this.setColor(color);
};
ns.HslRgbColorPicker.prototype.onKeydown_ = function (evt) {
var target = evt.target;
if (target.getAttribute('type').toLowerCase() === 'text') {
var value = parseInt(target.value, 10);
var dimension = target.dataset.dimension;
var isInputText = target.getAttribute('type').toLowerCase() === 'text';
if (isInputText && target.dataset.dimension) {
var model = target.dataset.model;
if (model === 'rgb' || model === 'hsv') {
var increment = this.getIncrement_(evt);
if (increment) {
var dimension = target.dataset.dimension;
var value = parseInt(target.value, 10);
this.updateColor_(value + increment, model, dimension);
}
}
}
};
ns.HslRgbColorPicker.prototype.getIncrement_ = function (evt) {
var increment = 0;
var key = pskl.service.keyboard.KeycodeTranslator.toChar(evt.keyCode);
if (key === 'up') {
value = value + 1;
increment = 1;
} else if (key === 'down') {
value = value - 1;
increment = -1;
}
value = this.normalizeDimension_(value, dimension);
if (evt.shiftKey) {
increment = increment * 5;
}
target.value = value;
this.onPickerChange_(evt);
return increment;
};
ns.HslRgbColorPicker.prototype.updateColor_ = function (inputValue, model, dimension) {
var value = this.toModelValue_(inputValue, model, dimension);
if (model === 'hsv' || model === 'rgb') {
if (!isNaN(value)) {
var color = this.getColor_(model);
color[dimension] = this.normalizeDimension_(value, dimension);
this.setColor(color);
}
} else if (model === 'hex') {
if (/^#([a-f0-9]{3}){1,2}$/i.test(value)) {
this.setColor(value);
}
}
};
ns.HslRgbColorPicker.prototype.onBlur_ = function (evt) {
var target = evt.target;
var isInputText = target.getAttribute('type').toLowerCase() === 'text';
if (isInputText && target.dataset.dimension) {
var model = target.dataset.model;
var dimension = target.dataset.dimension;
target.value = this.toInputValue_(model, dimension);
}
};
@ -86,6 +113,7 @@
this.hsvColor = this.toHsvColor_(inputColor);
this.tinyColor = this.toTinyColor_(inputColor);
this.rgbColor = this.tinyColor.toRgb();
this.updateInputs();
$(".color-picker-spectrum").spectrum("set", this.tinyColor);
@ -98,30 +126,85 @@
ns.HslRgbColorPicker.prototype.updateInputs = function () {
var inputs = this.container.querySelectorAll('input');
var rgb = this.tinyColor.toRgb();
for (var i = 0 ; i < inputs.length ; i++) {
var input = inputs[i];
var dimension = input.dataset.dimension;
var model = input.dataset.model;
if (model === 'rgb') {
input.value = rgb[dimension];
} else if (model === 'hsv') {
var value = this.hsvColor[dimension];
if (dimension === 'v' || dimension === 's') {
value = 100 * value;
var value = this.toInputValue_(model, dimension);
if (input.value != value) {
input.value = value;
}
input.value = Math.round(value);
}
if (input.getAttribute('type') === 'range') {
this.updateSliderBackground(input);
}
}
};
ns.HslRgbColorPicker.prototype.toInputValue_ = function (model, dimension) {
var value;
if (model === 'rgb' || model === 'hsv') {
var color = this.getColor_(model);
value = color[dimension];
if (dimension === 'v' || dimension === 's') {
value = 100 * value;
}
value = Math.round(value);
} else if (model === 'hex') {
value = this.tinyColor.toHexString(true);
}
return value;
};
ns.HslRgbColorPicker.prototype.toModelValue_ = function (value, model, dimension) {
var modelValue;
if (model === 'rgb' || model === 'hsv') {
modelValue = parseInt(value, 10);
if (dimension === 'v' || dimension === 's') {
modelValue = modelValue/100;
}
} else if (model === 'hex') {
modelValue = value;
}
return modelValue;
};
ns.HslRgbColorPicker.prototype.toTinyColor_ = function (color) {
var isTinyColor = typeof color == 'object' && color.hasOwnProperty('_tc_id');
if (isTinyColor) {
return color;
} else {
return window.tinycolor(pskl.utils.copy(color));
}
};
ns.HslRgbColorPicker.prototype.toHsvColor_ = function (color) {
var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color));
if (isHsvColor) {
return {
h : this.normalizeDimension_(color.h, 'h'),
s : this.normalizeDimension_(color.s, 's'),
v : this.normalizeDimension_(color.v, 'v')
};
} else {
return this.toTinyColor_(color).toHsv();
}
};
ns.HslRgbColorPicker.prototype.normalizeDimension_ = function (value, dimension) {
var range = this.getDimensionRange_(dimension);
return Math.max(range[0], Math.min(range[1], value));
};
/**
* Update background colors for range inputs
*/
ns.HslRgbColorPicker.prototype.updateSliderBackground = function (slider) {
var dimension = slider.dataset.dimension;
var model = slider.dataset.model;
@ -135,20 +218,13 @@
};
ns.HslRgbColorPicker.prototype.getSliderBackgroundColors_ = function (model, dimension) {
var start, end;
if (model === 'hsv') {
start = JSON.parse(JSON.stringify(this.hsvColor));
start[dimension] = 0;
var color = this.getColor_(model);
var start = pskl.utils.copy(color);
var end = pskl.utils.copy(color);
end = JSON.parse(JSON.stringify(this.hsvColor));
end[dimension] = 1;
} else {
start = this.tinyColor.toRgb();
start[dimension] = 0;
end = this.tinyColor.toRgb();
end[dimension] = 255;
}
var range = this.getDimensionRange_(dimension);
start[dimension] = range[0];
end[dimension] = range[1];
return {
start : window.tinycolor(start).toRgbString(),
@ -156,39 +232,24 @@
};
};
ns.HslRgbColorPicker.prototype.toTinyColor_ = function (color) {
if (typeof color == "object" && color.hasOwnProperty("_tc_id")) {
ns.HslRgbColorPicker.prototype.getDimensionRange_ = function (d) {
if (d === 'h') {
return [0, 359];
} else if (d === 's' || d === 'v') {
return [0, 1];
} else if (d === 'r' || d === 'g' || d === 'b') {
return [0, 255];
}
};
ns.HslRgbColorPicker.prototype.getColor_ = function (model) {
var color;
if (model === 'hsv') {
color = this.hsvColor;
} else if (model === 'rgb'){
color = this.rgbColor;
}
return color;
} else {
return window.tinycolor(JSON.parse(JSON.stringify(color)));
}
};
ns.HslRgbColorPicker.prototype.toHsvColor_ = function (color) {
var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color));
if (isHsvColor) {
return {
h : Math.max(0, Math.min(359, color.h)),
s : Math.max(0, Math.min(1, color.s)),
v : Math.max(0, Math.min(1, color.v))
};
} else {
return this.toTinyColor_(color).toHsv();
}
};
ns.HslRgbColorPicker.prototype.normalizeDimension_ = function (value, dimension) {
var ranges = {
'h' : [0, 359],
's' : [0, 100],
'v' : [0, 100],
'r' : [0, 255],
'g' : [0, 255],
'b' : [0, 255]
};
var range = ranges[dimension];
return Math.max(range[0], Math.min(range[1], value));
} ;
})();

View file

@ -25,6 +25,9 @@
<ul class="colors-list"></ul>
<div class="color-picker-container">
<div class="color-picker-spectrum"></div>
<div class="color-picker-input">
<input type="text" data-model="hex" data-dimension="*" class="textfield uppercase" value="#000000" />
</div>
<div class="color-picker-slider">
<span>H</span>
<input type="range" data-model="hsv" data-dimension="h" value="0" min="0" max="359" tabindex="-1"/>