Newer
Older
Angie Byron
committed
(function ($) {
Drupal.behaviors.color = {
Angie Byron
committed
attach: function (context, settings) {
// This behavior attaches by ID, so is only valid once on a page.
Dries Buytaert
committed
var form = $('#system-theme-settings .color-form', context).once('color');
if (form.length == 0) {
return;
}
var inputs = [];
var hooks = [];
var locks = [];
var focused = null;
// Add Farbtastic.
$(form).prepend('<div id="placeholder"></div>').addClass('color-processed');
var farb = $.farbtastic('#placeholder');
// Decode reference colors to HSL.
var reference = settings.color.reference;
for (i in reference) {
reference[i] = farb.RGBToHSL(farb.unpack(reference[i]));
}
Dries Buytaert
committed
// Build a preview.
var height = [];
var width = [];
// Loop through all defined gradients.
for (i in settings.gradients) {
// Add element to display the gradient.
$('#preview').once('color').append('<div id="gradient-' + i + '"></div>');
var gradient = $('#preview #gradient-' + i);
// Add height of current gradient to the list (divided by 10).
height.push(parseInt(gradient.css('height'), 10) / 10);
// Add width of current gradient to the list (divided by 10).
width.push(parseInt(gradient.css('width'), 10) / 10);
// Add rows (or columns for horizontal gradients).
// Each gradient line should have a height (or width for horizontal
// gradients) of 10px (because we divided the height/width by 10 above).
for (j = 0; j < (settings.gradients[i]['direction'] == 'vertical' ? height[i] : width[i]); ++j) {
gradient.append('<div class="gradient-line"></div>');
}
}
Dries Buytaert
committed
// Set up colorScheme selector.
Angie Byron
committed
$('#edit-scheme', form).change(function () {
var schemes = settings.color.schemes, colorScheme = this.options[this.selectedIndex].value;
if (colorScheme != '' && schemes[colorScheme]) {
// Get colors of active scheme.
colors = schemes[colorScheme];
for (field_name in colors) {
callback($('#edit-palette-' + field_name), colors[field_name], false, true);
}
preview();
});
/**
* Render the preview.
*/
function preview() {
Drupal.color.callback(context, settings, form, farb, height, width);
Dries Buytaert
committed
/**
* Shift a given color, using a reference pair (ref in HSL).
*
* This algorithm ensures relative ordering on the saturation and luminance
* axes is preserved, and performs a simple hue shift.
*
* It is also symmetrical. If: shift_color(c, a, b) == d,
* then shift_color(d, b, a) == c.
*/
function shift_color(given, ref1, ref2) {
// Convert to HSL.
given = farb.RGBToHSL(farb.unpack(given));
// Hue: apply delta.
given[0] += ref2[0] - ref1[0];
// Saturation: interpolate.
if (ref1[1] == 0 || ref2[1] == 0) {
given[1] = ref2[1];
var d = ref1[1] / ref2[1];
if (d > 1) {
given[1] /= d;
}
else {
given[1] = 1 - (1 - given[1]) * d;
}
// Luminance: interpolate.
if (ref1[2] == 0 || ref2[2] == 0) {
given[2] = ref2[2];
var d = ref1[2] / ref2[2];
if (d > 1) {
given[2] /= d;
else {
given[2] = 1 - (1 - given[2]) * d;
Dries Buytaert
committed
}
return farb.pack(farb.HSLToRGB(given));
/**
* Callback for Farbtastic when a new color is chosen.
*/
function callback(input, color, propagate, colorScheme) {
// Set background/foreground colors.
$(input).css({
backgroundColor: color,
'color': farb.RGBToHSL(farb.unpack(color))[2] > 0.5 ? '#000' : '#fff'
});
Dries Buytaert
committed
// Change input value.
if ($(input).val() && $(input).val() != color) {
$(input).val(color);
// Update locked values.
if (propagate) {
i = input.i;
for (j = i + 1; ; ++j) {
if (!locks[j - 1] || $(locks[j - 1]).is('.unlocked')) break;
matched = shift_color(color, reference[input.key], reference[inputs[j].key]);
callback(inputs[j], matched, false);
}
for (j = i - 1; ; --j) {
if (!locks[j] || $(locks[j]).is('.unlocked')) break;
matched = shift_color(color, reference[input.key], reference[inputs[j].key]);
callback(inputs[j], matched, false);
}
// Update preview.
preview();
Dries Buytaert
committed
}
// Reset colorScheme selector.
if (!colorScheme) {
resetScheme();
}
}
}
Dries Buytaert
committed
/**
* Reset the color scheme selector.
*/
function resetScheme() {
Angie Byron
committed
$('#edit-scheme', form).each(function () {
this.selectedIndex = this.options.length - 1;
});
}
Dries Buytaert
committed
// Focus the Farbtastic on a particular field.
function focus() {
var input = this;
// Remove old bindings.
focused && $(focused).unbind('keyup', farb.updateValue)
.unbind('keyup', preview).unbind('keyup', resetScheme)
.parent().removeClass('item-selected');
// Add new bindings.
focused = this;
Angie Byron
committed
farb.linkTo(function (color) { callback(input, color, true, false); });
farb.setColor(this.value);
$(focused).keyup(farb.updateValue).keyup(preview).keyup(resetScheme)
.parent().addClass('item-selected');
}
Dries Buytaert
committed
// Initialize color fields.
$('#palette input.form-text', form)
Angie Byron
committed
.each(function () {
// Extract palette field name
this.key = this.id.substring(13);
// Link to color picker temporarily to initialize.
Angie Byron
committed
farb.linkTo(function () {}).setColor('#000').linkTo(this);
// Add lock.
var i = inputs.length;
if (inputs.length) {
var lock = $('<div class="lock"></div>').toggle(
Angie Byron
committed
function () {
$(this).addClass('unlocked');
$(hooks[i - 1]).attr('class',
locks[i - 2] && $(locks[i - 2]).is(':not(.unlocked)') ? 'hook up' : 'hook'
);
$(hooks[i]).attr('class',
locks[i] && $(locks[i]).is(':not(.unlocked)') ? 'hook down' : 'hook'
);
},
Angie Byron
committed
function () {
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
$(this).removeClass('unlocked');
$(hooks[i - 1]).attr('class',
locks[i - 2] && $(locks[i - 2]).is(':not(.unlocked)') ? 'hook both' : 'hook down'
);
$(hooks[i]).attr('class',
locks[i] && $(locks[i]).is(':not(.unlocked)') ? 'hook both' : 'hook up'
);
}
);
$(this).after(lock);
locks.push(lock);
};
// Add hook.
var hook = $('<div class="hook"></div>');
$(this).after(hook);
hooks.push(hook);
$(this).parent().find('.lock').click();
this.i = i;
inputs.push(this);
})
.focus(focus);
$('#palette label', form);
// Focus first color.
focus.call(inputs[0]);
// Render preview.
preview();
}
Dries Buytaert
committed
};
})(jQuery);