color.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /**
  2. * @file
  3. * Attaches the behaviors for the Color module.
  4. */
  5. (function ($) {
  6. Drupal.behaviors.color = {
  7. attach: function (context, settings) {
  8. var i, j, colors, field_name;
  9. // This behavior attaches by ID, so is only valid once on a page.
  10. var form = $('#system-theme-settings .color-form', context).once('color');
  11. if (form.length == 0) {
  12. return;
  13. }
  14. var inputs = [];
  15. var hooks = [];
  16. var locks = [];
  17. var focused = null;
  18. // Add Farbtastic.
  19. $(form).prepend('<div id="placeholder"></div>').addClass('color-processed');
  20. var farb = $.farbtastic('#placeholder');
  21. // Decode reference colors to HSL.
  22. var reference = settings.color.reference;
  23. for (i in reference) {
  24. reference[i] = farb.RGBToHSL(farb.unpack(reference[i]));
  25. }
  26. // Build a preview.
  27. var height = [];
  28. var width = [];
  29. // Loop through all defined gradients.
  30. for (i in settings.gradients) {
  31. // Add element to display the gradient.
  32. $('#preview').once('color').append('<div id="gradient-' + i + '"></div>');
  33. var gradient = $('#preview #gradient-' + i);
  34. // Add height of current gradient to the list (divided by 10).
  35. height.push(parseInt(gradient.css('height'), 10) / 10);
  36. // Add width of current gradient to the list (divided by 10).
  37. width.push(parseInt(gradient.css('width'), 10) / 10);
  38. // Add rows (or columns for horizontal gradients).
  39. // Each gradient line should have a height (or width for horizontal
  40. // gradients) of 10px (because we divided the height/width by 10 above).
  41. for (j = 0; j < (settings.gradients[i]['direction'] == 'vertical' ? height[i] : width[i]); ++j) {
  42. gradient.append('<div class="gradient-line"></div>');
  43. }
  44. }
  45. // Fix preview background in IE6.
  46. if (navigator.appVersion.match(/MSIE [0-6]\./)) {
  47. var e = $('#preview #img')[0];
  48. var image = e.currentStyle.backgroundImage;
  49. e.style.backgroundImage = 'none';
  50. e.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image.substring(5, image.length - 2) + "')";
  51. }
  52. // Set up colorScheme selector.
  53. $('#edit-scheme', form).change(function () {
  54. var schemes = settings.color.schemes, colorScheme = this.options[this.selectedIndex].value;
  55. if (colorScheme != '' && schemes[colorScheme]) {
  56. // Get colors of active scheme.
  57. colors = schemes[colorScheme];
  58. for (field_name in colors) {
  59. callback($('#edit-palette-' + field_name), colors[field_name], false, true);
  60. }
  61. preview();
  62. }
  63. });
  64. /**
  65. * Renders the preview.
  66. */
  67. function preview() {
  68. Drupal.color.callback(context, settings, form, farb, height, width);
  69. }
  70. /**
  71. * Shifts a given color, using a reference pair (ref in HSL).
  72. *
  73. * This algorithm ensures relative ordering on the saturation and luminance
  74. * axes is preserved, and performs a simple hue shift.
  75. *
  76. * It is also symmetrical. If: shift_color(c, a, b) == d, then
  77. * shift_color(d, b, a) == c.
  78. */
  79. function shift_color(given, ref1, ref2) {
  80. // Convert to HSL.
  81. given = farb.RGBToHSL(farb.unpack(given));
  82. // Hue: apply delta.
  83. given[0] += ref2[0] - ref1[0];
  84. // Saturation: interpolate.
  85. if (ref1[1] == 0 || ref2[1] == 0) {
  86. given[1] = ref2[1];
  87. }
  88. else {
  89. var d = ref1[1] / ref2[1];
  90. if (d > 1) {
  91. given[1] /= d;
  92. }
  93. else {
  94. given[1] = 1 - (1 - given[1]) * d;
  95. }
  96. }
  97. // Luminance: interpolate.
  98. if (ref1[2] == 0 || ref2[2] == 0) {
  99. given[2] = ref2[2];
  100. }
  101. else {
  102. var d = ref1[2] / ref2[2];
  103. if (d > 1) {
  104. given[2] /= d;
  105. }
  106. else {
  107. given[2] = 1 - (1 - given[2]) * d;
  108. }
  109. }
  110. return farb.pack(farb.HSLToRGB(given));
  111. }
  112. /**
  113. * Callback for Farbtastic when a new color is chosen.
  114. */
  115. function callback(input, color, propagate, colorScheme) {
  116. var matched;
  117. // Set background/foreground colors.
  118. $(input).css({
  119. backgroundColor: color,
  120. 'color': farb.RGBToHSL(farb.unpack(color))[2] > 0.5 ? '#000' : '#fff'
  121. });
  122. // Change input value.
  123. if ($(input).val() && $(input).val() != color) {
  124. $(input).val(color);
  125. // Update locked values.
  126. if (propagate) {
  127. i = input.i;
  128. for (j = i + 1; ; ++j) {
  129. if (!locks[j - 1] || $(locks[j - 1]).is('.unlocked')) break;
  130. matched = shift_color(color, reference[input.key], reference[inputs[j].key]);
  131. callback(inputs[j], matched, false);
  132. }
  133. for (j = i - 1; ; --j) {
  134. if (!locks[j] || $(locks[j]).is('.unlocked')) break;
  135. matched = shift_color(color, reference[input.key], reference[inputs[j].key]);
  136. callback(inputs[j], matched, false);
  137. }
  138. // Update preview.
  139. preview();
  140. }
  141. // Reset colorScheme selector.
  142. if (!colorScheme) {
  143. resetScheme();
  144. }
  145. }
  146. }
  147. /**
  148. * Resets the color scheme selector.
  149. */
  150. function resetScheme() {
  151. $('#edit-scheme', form).each(function () {
  152. this.selectedIndex = this.options.length - 1;
  153. });
  154. }
  155. /**
  156. * Focuses Farbtastic on a particular field.
  157. */
  158. function focus() {
  159. var input = this;
  160. // Remove old bindings.
  161. focused && $(focused).unbind('keyup', farb.updateValue)
  162. .unbind('keyup', preview).unbind('keyup', resetScheme)
  163. .parent().removeClass('item-selected');
  164. // Add new bindings.
  165. focused = this;
  166. farb.linkTo(function (color) { callback(input, color, true, false); });
  167. farb.setColor(this.value);
  168. $(focused).keyup(farb.updateValue).keyup(preview).keyup(resetScheme)
  169. .parent().addClass('item-selected');
  170. }
  171. // Initialize color fields.
  172. $('#palette input.form-text', form)
  173. .each(function () {
  174. // Extract palette field name
  175. this.key = this.id.substring(13);
  176. // Link to color picker temporarily to initialize.
  177. farb.linkTo(function () {}).setColor('#000').linkTo(this);
  178. // Add lock.
  179. var i = inputs.length;
  180. if (inputs.length) {
  181. var lock = $('<div class="lock"></div>').toggle(
  182. function () {
  183. $(this).addClass('unlocked');
  184. $(hooks[i - 1]).attr('class',
  185. locks[i - 2] && $(locks[i - 2]).is(':not(.unlocked)') ? 'hook up' : 'hook'
  186. );
  187. $(hooks[i]).attr('class',
  188. locks[i] && $(locks[i]).is(':not(.unlocked)') ? 'hook down' : 'hook'
  189. );
  190. },
  191. function () {
  192. $(this).removeClass('unlocked');
  193. $(hooks[i - 1]).attr('class',
  194. locks[i - 2] && $(locks[i - 2]).is(':not(.unlocked)') ? 'hook both' : 'hook down'
  195. );
  196. $(hooks[i]).attr('class',
  197. locks[i] && $(locks[i]).is(':not(.unlocked)') ? 'hook both' : 'hook up'
  198. );
  199. }
  200. );
  201. $(this).after(lock);
  202. locks.push(lock);
  203. };
  204. // Add hook.
  205. var hook = $('<div class="hook"></div>');
  206. $(this).after(hook);
  207. hooks.push(hook);
  208. $(this).parent().find('.lock').click();
  209. this.i = i;
  210. inputs.push(this);
  211. })
  212. .focus(focus);
  213. $('#palette label', form);
  214. // Focus first color.
  215. focus.call(inputs[0]);
  216. // Render preview.
  217. preview();
  218. }
  219. };
  220. })(jQuery);