1<?php 2 3namespace dokuwiki\plugin\struct\types; 4 5use dokuwiki\plugin\struct\meta\ValidationException; 6 7class Color extends AbstractBaseType 8{ 9 protected $config = array( 10 'default' => '#ffffff' 11 ); 12 13 /** 14 * @inheritDoc 15 */ 16 public function validate($rawvalue) 17 { 18 $rawvalue = trim(strtolower($rawvalue)); 19 if (!preg_match('/^#[a-f0-9]{6}$/', $rawvalue)) { 20 throw new ValidationException('bad color specification'); 21 } 22 23 // ignore if default 24 if ($rawvalue == strtolower($this->config['default'])) { 25 $rawvalue = ''; 26 } 27 28 return $rawvalue; 29 } 30 31 /** 32 * @inheritDoc 33 */ 34 public function renderValue($value, \Doku_Renderer $R, $mode) 35 { 36 if ($mode == 'xhtml') { 37 $R->doc .= '<div title="' . hsc($value) . '" style="background-color:' . hsc($value) . ';" 38 class="struct_color"></div>'; 39 } else { 40 $R->cdata($value); 41 } 42 43 return true; 44 } 45 46 /** 47 * @inheritDoc 48 */ 49 public function renderMultiValue($values, \Doku_Renderer $R, $mode) 50 { 51 if ($mode == 'xhtml') { 52 foreach ($values as $value) { 53 $this->renderValue($value, $R, $mode); 54 } 55 } else { 56 $R->cdata(join(', ', $values)); 57 } 58 return true; 59 } 60 61 /** 62 * @inheritDoc 63 */ 64 public function valueEditor($name, $rawvalue, $htmlID) 65 { 66 if (!preg_match('/^#[a-f0-9]{6}$/', $rawvalue)) { 67 // any non-color (eg. from a previous type) should default to the default 68 $rawvalue = $this->config['default']; 69 } 70 71 $params = array( 72 'name' => $name, 73 'value' => $rawvalue, 74 'class' => 'struct_color', 75 'type' => 'color', 76 'id' => $htmlID 77 ); 78 $attributes = buildAttributes($params, true); 79 return "<input $attributes />"; 80 } 81 82 /** 83 * @inheritDoc 84 */ 85 public function renderTagCloudLink($value, \Doku_Renderer $R, $mode, $page, $filter, $weight) 86 { 87 $color = $this->displayValue($value); 88 if ($mode == 'xhtml') { 89 $url = wl($page, $filter); 90 $style = "background-color:$color;"; 91 $R->doc .= "<a class='struct_color_tagcloud' href='$url' style='$style'> 92 <span class='a11y'>$color</span> 93 </a>"; 94 return; 95 } 96 $R->internallink("$page?$filter", $color); 97 } 98 99 100 /** 101 * Sort by the hue of a color, not by its hex-representation 102 */ 103 public function getSortString($value) 104 { 105 $hue = $this->getHue(parent::getSortString($value)); 106 return $hue; 107 } 108 109 /** 110 * Calculate the hue of a color to use it for sorting so we can sort similar colors together. 111 * 112 * @param string $color the color as #RRGGBB 113 * @return float|int 114 */ 115 protected function getHue($color) 116 { 117 if (!preg_match('/^#[0-9A-F]{6}$/i', $color)) { 118 return 0; 119 } 120 121 $red = hexdec(substr($color, 1, 2)); 122 $green = hexdec(substr($color, 3, 2)); 123 $blue = hexdec(substr($color, 5, 2)); 124 125 $min = min([$red, $green, $blue]); 126 $max = max([$red, $green, $blue]); 127 128 if ($max == $red) { 129 $hue = ($green - $blue) / ($max - $min); 130 } 131 if ($max == $green) { 132 $hue = 2 + ($blue - $red) / ($max - $min); 133 } 134 if ($max == $blue) { 135 $hue = 4 + ($red - $green) / ($max - $min); 136 } 137 $hue = $hue * 60; 138 if ($hue < 0) { 139 $hue += 360; 140 } 141 return $hue; 142 } 143} 144