Commit fa636c26 authored by IKEDA Soji's avatar IKEDA Soji
Browse files

Replace Sympa's home-made color picker with jQuery MiniColors.

parent 03c18237
......@@ -2481,6 +2481,26 @@ span.fa-stack i.fa-plus-circle {
color:[% color_15 %];
}
[%# jQuery minicolors ~%]
[%# Reassign metrics by Foundation, and apply monospace font. ~%]
.minicolors-theme-default .minicolors-input {
height: 2.4375rem;
padding-left: 2.5rem; /* LTR */
font-family: monospace, serif;
}
[dir=rtl] .minicolors-theme-default .minicolors-input {
padding-left: 1px;
padding-right: 2.5rem;
}
.minicolors-theme-default .minicolors-swatch {
top: 0.5rem;
left: 0.5rem; /* LTR */
height: 1.5rem;
width: 1.5rem;
}
[dir=rtl] .minicolors-theme-default .minicolors-swatch {
right: 0.5rem;
}
[%~# 419px %]
@media screen and (min-width: 0px) and (max-width: 26.125em) {
......
......@@ -32,11 +32,15 @@ var lang = '[% lang %]';
<script src="[% static_content_url %]/js/jquery.js?v3.2.1"></script>
<script src="[% static_content_url %]/js/jquery-migrate.js?v1.4.1"></script>
<script src="[% static_content_url %]/js/jquery-ui/jquery-ui.js?v1.12.1"></script>
[%# jqPlot ~%]
<script src="[% static_content_url %]/js/jqplot/jquery.jqplot.min.js?v1.0.8"></script>
<script src="[% static_content_url %]/js/jqplot/jqplot.categoryAxisRenderer.min.js?v1.0.8"></script>
<script src="[% static_content_url %]/js/jqplot/jqplot.barRenderer.min.js?v1.0.8"></script>
<script src="[% static_content_url %]/js/jqplot/jqplot.canvasAxisTickRenderer.min.js?v1.0.8"></script>
<script src="[% static_content_url %]/js/jqplot/jqplot.canvasTextRenderer.min.js?v1.0.8"></script>
[%# Color picker ~%]
<script src="[% static_content_url %]/js/jquery-minicolors/jquery.minicolors.min.js?v2.3.1"></script>
[%# Sympa ~%]
<script src="[% static_content_url %]/js/sympa.js?v[% version %]"></script>
[%# Foundation and other ui adaptation ~%]
......
<!-- head_ui.tt2 -->
[%# Jquery-ui ~%]
<link rel="stylesheet" href="[% static_content_url %]/js/jquery-ui/jquery-ui.css?v1.12.1" />
[%# Jqplot ~%]
[%# JqPlot ~%]
<link rel="stylesheet" href="[% static_content_url %]/js/jqplot/jquery.jqplot.css?v1.0.8" />
[%# Font css ~%]
[%# Color picker ~%]
<link rel="stylesheet" href="[% static_content_url %]/js/jquery-minicolors/jquery.minicolors.css?v2.3.1">
[%# Font CSS ~%]
<link rel="stylesheet" href="[% static_content_url %]/fonts/font-awesome/css/font-awesome.css?v4.3.0" />
<link rel="stylesheet" href="[% static_content_url %]/fonts/foundation-icons/foundation-icons.css?v3.0" />
[%# Foundation ~%]
......
This diff is collapsed.
......@@ -938,11 +938,25 @@ our %in_regexp = (
'ip' => Sympa::Regexps::host(),
 
## colors
'subaction_test' => '.*',
'subaction_reset' => '.*',
'subaction_install' => '.*',
'custom_color_value' => '\#[0-9a-fA-F]+',
'custom_color_number' => 'color_\w+',
'subaction_test' => '.*',
'subaction_reset' => '.*',
'subaction_install' => '.*',
'color_0' => '\#[0-9a-fA-F]+',
'color_1' => '\#[0-9a-fA-F]+',
'color_2' => '\#[0-9a-fA-F]+',
'color_3' => '\#[0-9a-fA-F]+',
'color_4' => '\#[0-9a-fA-F]+',
'color_5' => '\#[0-9a-fA-F]+',
'color_6' => '\#[0-9a-fA-F]+',
'color_7' => '\#[0-9a-fA-F]+',
'color_8' => '\#[0-9a-fA-F]+',
'color_9' => '\#[0-9a-fA-F]+',
'color_10' => '\#[0-9a-fA-F]+',
'color_11' => '\#[0-9a-fA-F]+',
'color_12' => '\#[0-9a-fA-F]+',
'color_13' => '\#[0-9a-fA-F]+',
'color_14' => '\#[0-9a-fA-F]+',
'color_15' => '\#[0-9a-fA-F]+',
 
## Custom attribute
'custom_attribute' => '.*',
......@@ -7182,41 +7196,23 @@ sub do_edit_template {
sub do_skinsedit {
wwslog('info', '');
 
# Checking families and other virtual hosts.
get_server_details();
if ($in{'editcolors'} and $in{'subaction'} eq 'reset') {
delete $session->{'custom_css'};
delete $param->{'session'}{'custom_css'};
delete $param->{'custom_css'};
foreach my $colornumber (0 .. 15) {
delete $session->{'color_' . $colornumber};
delete $param->{'session'}{'color_' . $colornumber};
$param->{'color_' . $colornumber} =
Conf::get_robot_conf($robot, 'color_' . $colornumber);
}
}
if ($in{'editcolors'} and $in{'subaction'} eq 'test') {
return unless $in{'custom_color_number'} =~ /color_/;
$param->{'custom_color_number'} = $in{'custom_color_number'};
$param->{'custom_color_value'} = $in{'custom_color_value'};
$param->{'custom_css'} = $session->{'custom_css'} = 1;
$session->{$in{'custom_color_number'}} = $in{'custom_color_value'};
$param->{$in{'custom_color_number'}} = $in{'custom_color_value'};
$param->{'custom_css'} = $session->{'custom_css'} = 1;
foreach my $colornumber (0 .. 15) {
if ($session->{'color_' . $colornumber}) {
$param->{'color_' . $colornumber} =
$param->{'session'}{'color_' . $colornumber} =
$session->{'color_' . $colornumber};
my $cn = 'color_' . $colornumber;
if ($in{$cn} and $in{$cn} =~ /\A#[0-9a-z]+\z/i) {
$param->{$cn} = $session->{$cn} = lc $in{$cn};
} elsif ($session->{$cn}) {
$param->{$cn} = $session->{$cn};
} else {
$param->{$cn} = $session->{$cn} =
Conf::get_robot_conf($robot, $cn);
}
}
return 1;
}
 
if ($in{'subaction'} eq 'install' or $in{'installcss'}) {
if ($in{'editcolors'} and $in{'subaction'} eq 'install') {
# Update config.
my @keys = grep { $session->{$_} } map { 'color_' . $_ } (0 .. 15);
foreach my $key (@keys) {
......@@ -7229,6 +7225,21 @@ sub do_skinsedit {
 
$param->{'css_result'} = 1;
}
if ($in{'editcolors'}
and ($in{'subaction'} eq 'install' or $in{'subaction'} eq 'reset')) {
delete $session->{'custom_css'};
delete $param->{'session'}{'custom_css'};
delete $param->{'custom_css'};
foreach my $colornumber (0 .. 15) {
delete $session->{'color_' . $colornumber};
delete $param->{'session'}{'color_' . $colornumber};
$param->{'color_' . $colornumber} =
Conf::get_robot_conf($robot, 'color_' . $colornumber);
}
}
return 1;
}
 
......
......@@ -1334,7 +1334,7 @@ our @params = (
'gettext_id' => 'Colors for web interface',
'gettext_comment' =>
'Colors are used in style sheet (CSS). They may be changed using web interface by listmasters.',
'default' => '#F7F7F7', # very light grey use in tables,
'default' => '#f7f7f7', # very light grey use in tables,
'vhost' => '1',
'db' => 'db_first',
},
......@@ -1344,12 +1344,12 @@ our @params = (
'db' => 'db_first',
},
{ 'name' => 'color_2',
'default' => '#004B94', # font color,
'default' => '#004b94', # font color,
'vhost' => '1',
'db' => 'db_first',
},
{ 'name' => 'color_3',
'default' => '#5E5E5E', # top boxe and footer box bacground color,
'default' => '#5e5e5e', # top boxe and footer box bacground color,
'vhost' => '1',
'db' => 'db_first',
},
......@@ -1359,7 +1359,7 @@ our @params = (
'db' => 'db_first',
},
{ 'name' => 'color_5',
'default' => '#0090E9',
'default' => '#0090e9',
'vhost' => '1',
'db' => 'db_first',
},
......@@ -1369,7 +1369,7 @@ our @params = (
'db' => 'db_first',
},
{ 'name' => 'color_7',
'default' => '#fff', # errorbackground color,
'default' => '#ffffff', # errorbackground color,
'vhost' => '1',
'db' => 'db_first',
},
......@@ -1394,17 +1394,17 @@ our @params = (
'db' => 'db_first',
},
{ 'name' => 'color_12',
'default' => '#FFE7E7',
'default' => '#ffe7e7',
'vhost' => '1',
'db' => 'db_first',
},
{ 'name' => 'color_13',
'default' => '#f48A7b', # input backgound | transparent,
'default' => '#f48a7b', # input backgound | transparent,
'vhost' => '1',
'db' => 'db_first',
},
{ 'name' => 'color_14',
'default' => '#ff9',
'default' => '#ffff99',
'vhost' => '1',
'db' => 'db_first',
},
......@@ -1415,7 +1415,7 @@ our @params = (
},
{ 'name' => 'dark_color',
'gettext_id' => 'Colors for web interface, obsoleted',
'default' => 'silver',
'default' => '#c0c0c0', # 'silver'
'vhost' => '1',
'db' => 'db_first',
},
......@@ -1440,7 +1440,7 @@ our @params = (
'db' => 'db_first',
},
{ 'name' => 'selected_color',
'default' => 'silver',
'default' => '#c0c0c0', # 'silver'
'vhost' => '1',
'db' => 'db_first',
},
......
......@@ -60,14 +60,6 @@ $(function() {
});
});
function chooseColorNumber(cn, cv) {
$('#custom_color_number').val(cn);
if (cv) {
$('#custom_color_value').val(cv);
$('#custom_color_value').trigger('change');
}
}
// check if rejecting quietly spams TODO
function check_reject_spam(form,warningId) {
if(form.elements['iConfirm'].checked) return true;
......@@ -108,415 +100,19 @@ $(function() {
});
});
// Here are some boring utility functions. The real code comes later.
function hexToRgb(hex_string, default_)
{
if (default_ == undefined)
{
default_ = null;
}
if (hex_string.substr(0, 1) == '#')
{
hex_string = hex_string.substr(1);
}
var r;
var g;
var b;
if (hex_string.length == 3)
{
r = hex_string.substr(0, 1);
r += r;
g = hex_string.substr(1, 1);
g += g;
b = hex_string.substr(2, 1);
b += b;
}
else if (hex_string.length == 6)
{
r = hex_string.substr(0, 2);
g = hex_string.substr(2, 2);
b = hex_string.substr(4, 2);
}
else
{
return default_;
}
r = parseInt(r, 16);
g = parseInt(g, 16);
b = parseInt(b, 16);
if (isNaN(r) || isNaN(g) || isNaN(b))
{
return default_;
}
else
{
return {r: r / 255, g: g / 255, b: b / 255};
}
}
function rgbToHex(r, g, b, includeHash)
{
r = Math.round(r * 255);
g = Math.round(g * 255);
b = Math.round(b * 255);
if (includeHash == undefined)
{
includeHash = true;
}
r = r.toString(16);
if (r.length == 1)
{
r = '0' + r;
}
g = g.toString(16);
if (g.length == 1)
{
g = '0' + g;
}
b = b.toString(16);
if (b.length == 1)
{
b = '0' + b;
}
return ((includeHash ? '#' : '') + r + g + b).toUpperCase();
}
var arVersion = navigator.appVersion.split("MSIE");
var version = parseFloat(arVersion[1]);
function fixPNG(myImage)
{
if ((version >= 5.5) && (version < 7) && (document.body.filters))
{
var node = document.createElement('span');
node.id = myImage.id;
node.className = myImage.className;
node.title = myImage.title;
node.style.cssText = myImage.style.cssText;
node.style.setAttribute('filter', "progid:DXImageTransform.Microsoft.AlphaImageLoader"
+ "(src=\'" + myImage.src + "\', sizingMethod='scale')");
node.style.fontSize = '0';
node.style.width = myImage.width.toString() + 'px';
node.style.height = myImage.height.toString() + 'px';
node.style.display = 'inline-block';
return node;
}
else
{
return myImage.cloneNode(false);
}
}
function trackDrag(node, handler)
{
function fixCoords(ev)
{
var e = ev.originalEvent.changedTouches
? ev.originalEvent.changedTouches[0] : ev;
x = e.pageX - $(node).offset().left;
y = e.pageY - $(node).offset().top;
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x > node.offsetWidth - 1) x = node.offsetWidth - 1;
if (y > node.offsetHeight - 1) y = node.offsetHeight - 1;
return {x: x, y: y};
}
var _pointer = (function()
{
if (window.navigator.pointerEnabled) // Pointer events (IE11+)
{
return {down: 'pointerdown', move: 'pointermove', up: 'pointerup'};
}
else if ('ontouchstart' in window) // Touch events
{
return {down: 'touchstart', move: 'touchmove', up: 'touchend'};
}
else
{
return {down: 'mousedown', move: 'mousemove', up: 'mouseup'};
}
})();
function mouseDown(ev)
{
var coords = fixCoords(ev);
var lastX = coords.x;
var lastY = coords.y;
handler(coords.x, coords.y);
function moveHandler(ev)
{
var coords = fixCoords(ev);
if (coords.x != lastX || coords.y != lastY)
{
lastX = coords.x;
lastY = coords.y;
handler(coords.x, coords.y);
}
}
function upHandler(ev)
{
$(document).off(_pointer.up, upHandler);
$(document).off(_pointer.move, moveHandler);
$(node).on(_pointer.down, mouseDown);
}
$(document).on(_pointer.up, upHandler);
$(document).on(_pointer.move, moveHandler);
$(node).off(_pointer.down, mouseDown);
if (ev.preventDefault) ev.preventDefault();
}
$(node).on(_pointer.down, mouseDown);
}
// This copyright statement applies to the following two functions,
// which are taken from MochiKit.
//
// Copyright 2005 Bob Ippolito <bob@redivi.com>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
function hsvToRgb(hue, saturation, value)
{
var red;
var green;
var blue;
if (value == 0.0)
{
red = 0;
green = 0;
blue = 0;
}
else
{
var i = Math.floor(hue * 6);
var f = (hue * 6) - i;
var p = value * (1 - saturation);
var q = value * (1 - (saturation * f));
var t = value * (1 - (saturation * (1 - f)));
switch (i)
{
case 1: red = q; green = value; blue = p; break;
case 2: red = p; green = value; blue = t; break;
case 3: red = p; green = q; blue = value; break;
case 4: red = t; green = p; blue = value; break;
case 5: red = value; green = p; blue = q; break;
case 6: // fall through
case 0: red = value; green = t; blue = p; break;
}
}
return {r: red, g: green, b: blue};
}
function rgbToHsv(red, green, blue)
{
var max = Math.max(Math.max(red, green), blue);
var min = Math.min(Math.min(red, green), blue);
var hue;
var saturation;
var value = max;
if (min == max)
{
hue = 0;
saturation = 0;
}
else
{
var delta = (max - min);
saturation = delta / max;
if (red == max)
{
hue = (green - blue) / delta;
}
else if (green == max)
{
hue = 2 + ((blue - red) / delta);
}
else
{
hue = 4 + ((red - green) / delta);
}
hue /= 6;
if (hue < 0)
{
hue += 1;
}
if (hue > 1)
{
hue -= 1;
}
}
return {
h: hue,
s: saturation,
v: value
};
}
// The real code begins here.
var huePositionImg = document.createElement('img');
huePositionImg.galleryImg = false;
huePositionImg.width = 35;
huePositionImg.height = 11;
huePositionImg.src = sympa.icons_url + '/position.png';
huePositionImg.style.position = 'absolute';
var hueSelectorImg = document.createElement('img');
hueSelectorImg.galleryImg = false;
hueSelectorImg.width = 35;
hueSelectorImg.height = 200;
hueSelectorImg.src = sympa.icons_url + '/h.png';
hueSelectorImg.style.display = 'block';
var satValImg = document.createElement('img');
satValImg.galleryImg = false;
satValImg.width = 200;
satValImg.height = 200;
satValImg.src = sympa.icons_url + '/sv.png';
satValImg.style.display = 'block';
var crossHairsImg = document.createElement('img');
crossHairsImg.galleryImg = false;
crossHairsImg.width = 21;
crossHairsImg.height = 21;
crossHairsImg.src = sympa.icons_url + '/crosshairs.png';
crossHairsImg.style.position = 'absolute';
function makeColorSelector(inputBox)
{
var rgb, hsv
function colorChanged()
{
var hex = rgbToHex(rgb.r, rgb.g, rgb.b);
var hueRgb = hsvToRgb(hsv.h, 1, 1);
var hueHex = rgbToHex(hueRgb.r, hueRgb.g, hueRgb.b);
previewDiv.style.background = hex;
inputBox.value = hex;
satValDiv.style.background = hueHex;
crossHairs.style.left = ((hsv.v*199)-10).toString() + 'px';
crossHairs.style.top = (((1-hsv.s)*199)-10).toString() + 'px';
huePos.style.top = ((hsv.h*199)-5).toString() + 'px';
}
function rgbChanged()
{
hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
colorChanged();
}
function hsvChanged()
{
rgb = hsvToRgb(hsv.h, hsv.s, hsv.v);
colorChanged();
}
var colorSelectorDiv = document.createElement('div');
colorSelectorDiv.style.padding = '15px';
colorSelectorDiv.style.position = 'relative';
colorSelectorDiv.style.height = '275px';
colorSelectorDiv.style.width = '250px';
var satValDiv = document.createElement('div');
satValDiv.style.position = 'relative';
satValDiv.style.width = '200px';
satValDiv.style.height = '200px';
var newSatValImg = fixPNG(satValImg);
satValDiv.appendChild(newSatValImg);
var crossHairs = crossHairsImg.cloneNode(false);
satValDiv.appendChild(crossHairs);
function satValDragged(x, y)
{
hsv.s = 1-(y/199);
hsv.v = (x/199);
hsvChanged();
}
trackDrag(satValDiv, satValDragged)
colorSelectorDiv.appendChild(satValDiv);
var hueDiv = document.createElement('div');
hueDiv.style.position = 'absolute';
hueDiv.style.left = '230px';
hueDiv.style.top = '15px';
hueDiv.style.width = '35px';
hueDiv.style.height = '200px';
var huePos = fixPNG(huePositionImg);