From 29a93b8c08b0f2d8fe772764119c95eef56aa972 Mon Sep 17 00:00:00 2001
From: Angie Byron <webchick@24967.no-reply.drupal.org>
Date: Sat, 3 Apr 2010 08:05:08 +0000
Subject: [PATCH] #693504 by stBorchert, ksenzee, dixon_ | jarek, joachim,
 EvanDonovan, eigentor, sun, dmitrig01, et al.: Added support to color.module
 for flexible color schemes and gradients, and removed hard-coded assumptions
 about Garland.

---
 modules/color/color.js           |  95 +++++++++-------
 modules/color/color.module       |  95 ++++++++++------
 modules/color/color.test         |  12 +++
 themes/garland/color/color.inc   | 180 ++++++++++++++++++++++++++++---
 themes/garland/color/preview.css |   6 +-
 5 files changed, 297 insertions(+), 91 deletions(-)

diff --git a/modules/color/color.js b/modules/color/color.js
index f6ebc8774ada..8cb7451573b8 100644
--- a/modules/color/color.js
+++ b/modules/color/color.js
@@ -3,6 +3,7 @@
 
 Drupal.behaviors.color = {
   attach: function (context, settings) {
+    var i, colors, field_name;
     // This behavior attaches by ID, so is only valid once on a page.
     var form = $('#system-theme-settings .color-form', context).once('color');
     if (form.length == 0) {
@@ -24,11 +25,23 @@ Drupal.behaviors.color = {
     }
 
     // Build a preview.
-    $('#preview').once('color').append('<div id="gradient"></div>');
-    var gradient = $('#preview #gradient');
-    var h = parseInt(gradient.css('height'), 10) / 10;
-    for (i = 0; i < h; ++i) {
-      gradient.append('<div class="gradient-line"></div>');
+    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>');
+      }
     }
 
     // Fix preview background in IE6.
@@ -39,13 +52,14 @@ Drupal.behaviors.color = {
       e.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image.substring(5, image.length - 2) + "')";
     }
 
-    // Set up colorscheme selector.
+    // Set up colorScheme selector.
     $('#edit-scheme', form).change(function () {
-      var colors = this.options[this.selectedIndex].value;
-      if (colors != '') {
-        colors = colors.split(',');
-        for (i in colors) {
-          callback(inputs[i], colors[i], false, true);
+      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();
       }
@@ -56,29 +70,31 @@ Drupal.behaviors.color = {
      */
     function preview() {
       // Solid background.
-      $('#preview', form).css('backgroundColor', inputs[0].value);
+      $('#preview', form).css('backgroundColor', $('#palette input[name="palette[base]"]', form).val());
 
       // Text preview
-      $('#text', form).css('color', inputs[4].value);
-      $('#text a, #text h2', form).css('color', inputs[1].value);
-
-      // Set up gradient.
-      var top = farb.unpack(inputs[2].value);
-      var bottom = farb.unpack(inputs[3].value);
-      if (top && bottom) {
-        var delta = [];
-        for (i in top) {
-          delta[i] = (bottom[i] - top[i]) / h;
-        }
-        var accum = top;
-
-        // Render gradient lines.
-        $('#gradient > div', form).each(function () {
-          for (i in accum) {
-            accum[i] += delta[i];
+      $('#text', form).css('color', $('#palette input[name="palette[text]"]', form).val());
+      $('#text a, #text h2', form).css('color', $('#palette input[name="palette[link]"]', form).val());
+
+      // Set up gradients if there are some.
+      var color_start, color_end;
+      for (i in settings.gradients) {
+        color_start = farb.unpack($('#palette input[name="palette[' + settings.gradients[i]['colors'][0] + ']"]', form).val());
+        color_end = farb.unpack($('#palette input[name="palette[' + settings.gradients[i]['colors'][1] + ']"]', form).val());
+        if (color_start && color_end) {
+          var delta = [];
+          for (j in color_start) {
+            delta[j] = (color_end[j] - color_start[j]) / (settings.gradients[i]['vertical'] ? height[i] : width[i]);
           }
-          this.style.backgroundColor = farb.pack(accum);
-        });
+          var accum = color_start;
+          // Render gradient lines.
+          $('#gradient-' + i + ' > div', form).each(function () {
+            for (j in accum) {
+              accum[j] += delta[j];
+            }
+            this.style.backgroundColor = farb.pack(accum);
+          });
+        }
       }
     }
 
@@ -132,7 +148,8 @@ Drupal.behaviors.color = {
     /**
      * Callback for Farbtastic when a new color is chosen.
      */
-    function callback(input, color, propagate, colorscheme) {
+    function callback(input, color, propagate, colorScheme) {
+      var i, j, matched;
       // Set background/foreground colors.
       $(input).css({
         backgroundColor: color,
@@ -140,20 +157,20 @@ Drupal.behaviors.color = {
       });
 
       // Change input value.
-      if (input.value && input.value != color) {
-        input.value = color;
+      if ($(input).val() && $(input).val() != color) {
+        $(input).val(color);
 
         // Update locked values.
         if (propagate) {
-          var i = input.i;
+          i = input.i;
           for (j = i + 1; ; ++j) {
             if (!locks[j - 1] || $(locks[j - 1]).is('.unlocked')) break;
-            var matched = shift_color(color, reference[input.key], reference[inputs[j].key]);
+            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;
-            var matched = shift_color(color, reference[input.key], reference[inputs[j].key]);
+            matched = shift_color(color, reference[input.key], reference[inputs[j].key]);
             callback(inputs[j], matched, false);
           }
 
@@ -161,8 +178,8 @@ Drupal.behaviors.color = {
           preview();
         }
 
-        // Reset colorscheme selector.
-        if (!colorscheme) {
+        // Reset colorScheme selector.
+        if (!colorScheme) {
           resetScheme();
         }
       }
diff --git a/modules/color/color.module b/modules/color/color.module
index ce990d19024b..04d8e9bb48ce 100644
--- a/modules/color/color.module
+++ b/modules/color/color.module
@@ -128,12 +128,8 @@ function color_get_info($theme) {
  */
 function color_get_palette($theme, $default = FALSE) {
   // Fetch and expand default palette.
-  $fields = array('base', 'link', 'top', 'bottom', 'text');
   $info = color_get_info($theme);
-  $keys = array_keys($info['schemes']);
-  foreach (explode(',', array_shift($keys)) as $k => $scheme) {
-    $palette[$fields[$k]] = $scheme;
-  }
+  $palette = $info['schemes']['default']['colors'];
 
   // Load variable.
   return $default ? $palette : variable_get('color_' . $theme . '_palette', $palette);
@@ -146,18 +142,39 @@ function color_scheme_form($complete_form, &$form_state, $theme) {
   $base = drupal_get_path('module', 'color');
   $info = color_get_info($theme);
 
+  $info['schemes'][''] = array('title' => t('Custom'), 'colors' => array());
+  $color_sets = array();
+  $schemes = array();
+  foreach ($info['schemes'] as $key => $scheme) {
+    $color_sets[$key] = $scheme['title'];
+    $schemes[$key] = $scheme['colors'];
+    $schemes[$key] += $info['schemes']['default']['colors'];
+  }
+
   // See if we're using a predefined scheme.
-  $current = implode(',', variable_get('color_' . $theme . '_palette', array()));
   // Note: we use the original theme when the default scheme is chosen.
-  $current = isset($info['schemes'][$current]) ? $current : ($current == '' ? reset($info['schemes']) : '');
+  $current_scheme = variable_get('color_' . $theme . '_palette', array());
+  foreach ($schemes as $key => $scheme) {
+    if ($current_scheme == $scheme) {
+      $scheme_name = $key;
+      break;
+    }
+  }
+  if (empty($scheme_name)) {
+    if (empty($current_scheme)) {
+      $scheme_name = 'default';
+    }
+    else {
+      $scheme_name = '';
+    }
+  }
 
   // Add scheme selector.
-  $info['schemes'][''] = t('Custom');
   $form['scheme'] = array(
     '#type' => 'select',
     '#title' => t('Color set'),
-    '#options' => $info['schemes'],
-    '#default_value' => $current,
+    '#options' => $color_sets,
+    '#default_value' => $scheme_name,
     '#attached' => array(
       // Add Farbtastic color picker.
       'library' => array(
@@ -172,7 +189,11 @@ function color_scheme_form($complete_form, &$form_state, $theme) {
         $base . '/color.js',
         array(
           'data' => array(
-            'color' => array('reference' => color_get_palette($theme, TRUE)),
+            'color' => array(
+              'reference' => color_get_palette($theme, TRUE),
+              'schemes' => $schemes,
+            ),
+            'gradients' => $info['gradients'],
           ),
           'type' => 'setting',
         ),
@@ -182,21 +203,17 @@ function color_scheme_form($complete_form, &$form_state, $theme) {
 
   // Add palette fields.
   $palette = color_get_palette($theme);
-  $names = array(
-    'base' => t('Base color'),
-    'link' => t('Link color'),
-    'top' => t('Header top'),
-    'bottom' => t('Header bottom'),
-    'text' => t('Text color'),
-  );
+  $names = $info['fields'];
   $form['palette']['#tree'] = TRUE;
   foreach ($palette as $name => $value) {
-    $form['palette'][$name] = array(
-      '#type' => 'textfield',
-      '#title' => $names[$name],
-      '#default_value' => $value,
-      '#size' => 8,
-    );
+    if (isset($names[$name])) {
+      $form['palette'][$name] = array(
+        '#type' => 'textfield',
+        '#title' => $names[$name],
+        '#default_value' => $value,
+        '#size' => 8,
+      );
+    }
   }
   $form['theme'] = array('#type' => 'value', '#value' => $theme);
   $form['info'] = array('#type' => 'value', '#value' => $info);
@@ -251,10 +268,12 @@ function color_scheme_form_submit($form, &$form_state) {
   // Resolve palette.
   $palette = $form_state['values']['palette'];
   if ($form_state['values']['scheme'] != '') {
-    $scheme = explode(',', $form_state['values']['scheme']);
-    foreach ($palette as $k => $color) {
-      $palette[$k] = array_shift($scheme);
+    foreach ($palette as $key => $color) {
+      if (isset($info['schemes'][$form_state['values']['scheme']]['colors'][$key])) {
+        $palette[$key] = $info['schemes'][$form_state['values']['scheme']]['colors'][$key];
+      }
     }
+    $palette += $info['schemes']['default']['colors'];
   }
 
   // Make sure enough memory is available, if PHP's memory limit is compiled in.
@@ -450,7 +469,6 @@ function _color_save_stylesheet($file, $style, &$paths) {
  * Render images that match a given palette.
  */
 function _color_render_images($theme, &$info, &$paths, $palette) {
-
   // Prepare template image.
   $source = $paths['source'] . '/' . $info['base_image'];
   $source = imagecreatefrompng($source);
@@ -466,10 +484,23 @@ function _color_render_images($theme, &$info, &$paths, $palette) {
     imagefilledrectangle($target, $fill[0], $fill[1], $fill[0] + $fill[2], $fill[1] + $fill[3], _color_gd($target, $palette[$color]));
   }
 
-  // Render gradient.
-  for ($y = 0; $y < $info['gradient'][3]; ++$y) {
-    $color = _color_blend($target, $palette['top'], $palette['bottom'], $y / ($info['gradient'][3] - 1));
-    imagefilledrectangle($target, $info['gradient'][0], $info['gradient'][1] + $y, $info['gradient'][0] + $info['gradient'][2], $info['gradient'][1] + $y + 1, $color);
+  // Render gradients.
+  foreach ($info['gradients'] as $gradient) {
+    // Get direction of the gradient.
+    if (isset($gradient['direction']) && $gradient['direction'] == 'horizontal') {
+      // Horizontal gradient.
+      for ($x = 0; $x < $gradient['dimension'][2]; $x++) {
+        $color = _color_blend($target, $palette[$gradient['colors'][0]], $palette[$gradient['colors'][1]], $x / ($gradient['dimension'][2] - 1));
+        imagefilledrectangle($target, ($gradient['dimension'][0] + $x), $gradient['dimension'][1], ($gradient['dimension'][0] + $x + 1), ($gradient['dimension'][1] + $gradient['dimension'][3]), $color);
+      }
+    }
+    else {
+      // Vertical gradient.
+      for ($y = 0; $y < $gradient['dimension'][3]; $y++) {
+        $color = _color_blend($target, $palette[$gradient['colors'][0]], $palette[$gradient['colors'][1]], $y / ($gradient['dimension'][3] - 1));
+        imagefilledrectangle($target, $gradient['dimension'][0], $gradient['dimension'][1] + $y, $gradient['dimension'][0] + $gradient['dimension'][2], $gradient['dimension'][1] + $y + 1, $color);
+      }
+    }
   }
 
   // Blend over template.
diff --git a/modules/color/color.test b/modules/color/color.test
index 7b01b80b95e9..d487be24bbc7 100644
--- a/modules/color/color.test
+++ b/modules/color/color.test
@@ -45,6 +45,18 @@ class ColorTestCase extends DrupalWebTestCase {
     $stylesheet_content = join("\n", file($stylesheets[0]));
     $matched = preg_match('/(.*color: #123456.*)/i', $stylesheet_content, $matches);
     $this->assertTrue($matched == 1, 'Make sure the color we changed is in the color stylesheet.');
+
+    $this->drupalGet('admin/appearance/settings/garland');
+    $this->assertResponse(200);
+    $edit['scheme'] = 'greenbeam';
+    $this->drupalPost('admin/appearance/settings/garland', $edit, t('Save configuration'));
+
+    $this->drupalGet('<front>');
+    $stylesheets = variable_get('color_' . $theme_key . '_stylesheets', array());
+    $stylesheet_content = join("\n", file($stylesheets[0]));
+    $matched = preg_match('/(.*color: #0c7a00.*)/i', $stylesheet_content, $matches);
+    $this->assertTrue($matched == 1, 'Make sure the color we changed is in the color stylesheet.');
+
   }
 
 }
diff --git a/themes/garland/color/color.inc b/themes/garland/color/color.inc
index 10d76dedda28..c23d3f0d6293 100644
--- a/themes/garland/color/color.inc
+++ b/themes/garland/color/color.inc
@@ -3,23 +3,160 @@
 
 $info = array(
 
+  // Available colors and color labels used in theme.
+  'fields' => array(
+    'base' => t('Base color'),
+    'link' => t('Link color'),
+    'top' => t('Header top'),
+    'bottom' => t('Header bottom'),
+    'text' => t('Text color'),
+  ),
   // Pre-defined color schemes.
   'schemes' => array(
-    '#0072b9,#027ac6,#2385c2,#5ab5ee,#494949' => t('Blue Lagoon (Default)'),
-    '#464849,#2f416f,#2a2b2d,#5d6779,#494949' => t('Ash'),
-    '#55c0e2,#000000,#085360,#007e94,#696969' => t('Aquamarine'),
-    '#d5b048,#6c420e,#331900,#971702,#494949' => t('Belgian Chocolate'),
-    '#3f3f3f,#336699,#6598cb,#6598cb,#000000' => t('Bluemarine'),
-    '#d0cb9a,#917803,#efde01,#e6fb2d,#494949' => t('Citrus Blast'),
-    '#0f005c,#434f8c,#4d91ff,#1a1575,#000000' => t('Cold Day'),
-    '#c9c497,#0c7a00,#03961e,#7be000,#494949' => t('Greenbeam'),
-    '#ffe23d,#a9290a,#fc6d1d,#a30f42,#494949' => t('Mediterrano'),
-    '#788597,#3f728d,#a9adbc,#d4d4d4,#707070' => t('Mercury'),
-    '#5b5fa9,#5b5faa,#0a2352,#9fa8d5,#494949' => t('Nocturnal'),
-    '#7db323,#6a9915,#b5d52a,#7db323,#191a19' => t('Olivia'),
-    '#12020b,#1b1a13,#f391c6,#f41063,#898080' => t('Pink Plastic'),
-    '#b7a0ba,#c70000,#a1443a,#f21107,#515d52' => t('Shiny Tomato'),
-    '#18583d,#1b5f42,#34775a,#52bf90,#2d2d2d' => t('Teal Top'),
+    'default' => array(
+      'title' => t('Blue Lagoon (Default)'),
+      'colors' => array(
+        'base' => '#0072b9',
+        'link' => '#027ac6',
+        'top' => '#2385c2',
+        'bottom' => '#5ab5ee',
+        'text' => '#494949',
+      ),
+    ),
+    'ash' => array(
+      'title' => t('Ash'),
+      'colors' => array(
+        'base' => '#464849',
+        'link' => '#2f416f',
+        'top' => '#2a2b2d',
+        'bottom' => '#5d6779',
+      ),
+    ),
+    'aquamarine' => array(
+      'title' => t('Aquamarine'),
+      'colors' => array(
+        'base' => '#55c0e2',
+        'link' => '#000000',
+        'text' => '#696969',
+        'top' => '#085360',
+        'bottom' => '#007e94',
+      ),
+    ),
+    'chocolate' => array(
+      'title' => t('Belgian Chocolate'),
+      'colors' => array(
+        'base' => '#d5b048',
+        'link' => '#6c420e',
+        'top' => '#331900',
+        'bottom' => '#971702',
+      ),
+    ),
+    'bluemarine' => array(
+      'title' => t('Bluemarine'),
+      'colors' => array(
+        'base' => '#3f3f3f',
+        'link' => '#336699',
+        'text' => '#000000',
+        'top' => '#6598cb',
+        'bottom' => '#6598cb',
+      ),
+    ),
+    'citrus' => array(
+      'title' => t('Citrus Blast'),
+      'colors' => array(
+        'base' => '#d0cb9a',
+        'link' => '#917803',
+        'top' => '#efde01',
+        'bottom' => '#e6fb2d',
+      ),
+    ),
+    'cold' => array(
+      'title' => t('Cold Day'),
+      'colors' => array(
+        'base' => '#0f005c',
+        'link' => '#434f8c',
+        'text' => '#000000',
+        'top' => '#4d91ff',
+        'bottom' => '#1a1575',
+      ),
+    ),
+    'greenbeam' => array(
+      'title' => t('Greenbeam'),
+      'colors' => array(
+        'base' => '#c9c497',
+        'link' => '#0c7a00',
+        'top' => '#03961e',
+        'bottom' => '#7be000',
+      ),
+    ),
+    'mediterrano' => array(
+      'title' => t('Mediterrano'),
+      'colors' => array(
+        'base' => '#ffe23d',
+        'link' => '#a9290a',
+        'top' => '#fc6d1d',
+        'bottom' => '#a30f42',
+      ),
+    ),
+    'mercury' => array(
+      'title' => t('Mercury'),
+      'colors' => array(
+        'base' => '#788597',
+        'link' => '#3f728d',
+        'top' => '#a9adbc',
+        'bottom' => '#d4d4d4',
+        'text' => '#707070',
+      ),
+    ),
+    'nocturnal' => array(
+      'title' => t('Nocturnal'),
+      'colors' => array(
+        'base' => '#5b5fa9',
+        'link' => '#5b5faa',
+        'top' => '#0a2352',
+        'bottom' => '#9fa8d5',
+      ),
+    ),
+    'olivia' => array(
+      'title' => t('Olivia'),
+      'colors' => array(
+        'base' => '#7db323',
+        'link' => '#6a9915',
+        'top' => '#b5d52a',
+        'bottom' => '#7db323',
+        'text' => '#191a19',
+      ),
+    ),
+    'pink_plastic' => array(
+      'title' => t('Pink Plastic'),
+      'colors' => array(
+        'base' => '#12020b',
+        'link' => '#1b1a13',
+        'top' => '#f391c6',
+        'bottom' => '#f41063',
+        'text' => '#898080',
+      ),
+    ),
+    'shiny_tomato' => array(
+      'title' => t('Shiny Tomato'),
+      'colors' => array(
+        'base' => '#b7a0ba',
+        'link' => '#c70000',
+        'top' => '#a1443a',
+        'bottom' => '#f21107',
+        'text' => '#515d52',
+      ),
+    ),
+    'teal_top' => array(
+      'title' => t('Teal Top'),
+      'colors' => array(
+        'base' => '#18583d',
+        'link' => '#1b5f42',
+        'top' => '#34775a',
+        'bottom' => '#52bf90',
+        'text' => '#2d2d2d',
+      ),
+    ),
   ),
 
   // Images to copy over.
@@ -35,8 +172,17 @@
     'style.css',
   ),
 
-  // Coordinates of gradient (x, y, width, height).
-  'gradient' => array(0, 37, 760, 121),
+  // Gradient definitions.
+  'gradients' => array(
+    array(
+      // (x, y, width, height).
+      'dimension' => array(0, 38, 760, 121),
+      // Direction of gradient ('vertical' or 'horizontal').
+      'direction' => 'vertical',
+      // Keys of colors to use for the gradient.
+      'colors' => array('top', 'bottom'),
+    ),
+  ),
 
   // Color areas to fill (x, y, width, height).
   'fill' => array(
diff --git a/themes/garland/color/preview.css b/themes/garland/color/preview.css
index 921f7125adcd..5e8681b439b4 100644
--- a/themes/garland/color/preview.css
+++ b/themes/garland/color/preview.css
@@ -6,10 +6,10 @@
   max-width: 100%;
 }
 #preview, #preview #img {
-  width: 596px;
+  width: 600px;
   height: 371px;
 }
-#preview #gradient {
+#preview #gradient-0 {
   position: absolute;
   left: 0;
   right: 0;
@@ -29,7 +29,7 @@
   position: relative;
   z-index: 3;
 }
-#preview #gradient .gradient-line {
+#preview #gradient-0 .gradient-line {
   height: 10px;
   overflow: hidden;
 }
-- 
GitLab