1: <?php
2:
3: /* W3C says:
4: [ // adjective and number must be in correct order, even if
5: // you could switch them without introducing ambiguity.
6: // some browsers support that syntax
7: [
8: <percentage> | <length> | left | center | right
9: ]
10: [
11: <percentage> | <length> | top | center | bottom
12: ]?
13: ] |
14: [ // this signifies that the vertical and horizontal adjectives
15: // can be arbitrarily ordered, however, there can only be two,
16: // one of each, or none at all
17: [
18: left | center | right
19: ] ||
20: [
21: top | center | bottom
22: ]
23: ]
24: top, left = 0%
25: center, (none) = 50%
26: bottom, right = 100%
27: */
28:
29: /* QuirksMode says:
30: keyword + length/percentage must be ordered correctly, as per W3C
31:
32: Internet Explorer and Opera, however, support arbitrary ordering. We
33: should fix it up.
34:
35: Minor issue though, not strictly necessary.
36: */
37:
38: // control freaks may appreciate the ability to convert these to
39: // percentages or something, but it's not necessary
40:
41: /**
42: * Validates the value of background-position.
43: */
44: class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
45: {
46:
47: /**
48: * @type HTMLPurifier_AttrDef_CSS_Length
49: */
50: protected $length;
51:
52: /**
53: * @type HTMLPurifier_AttrDef_CSS_Percentage
54: */
55: protected $percentage;
56:
57: public function __construct()
58: {
59: $this->length = new HTMLPurifier_AttrDef_CSS_Length();
60: $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage();
61: }
62:
63: /**
64: * @param string $string
65: * @param HTMLPurifier_Config $config
66: * @param HTMLPurifier_Context $context
67: * @return bool|string
68: */
69: public function validate($string, $config, $context)
70: {
71: $string = $this->parseCDATA($string);
72: $bits = explode(' ', $string);
73:
74: $keywords = array();
75: $keywords['h'] = false; // left, right
76: $keywords['v'] = false; // top, bottom
77: $keywords['ch'] = false; // center (first word)
78: $keywords['cv'] = false; // center (second word)
79: $measures = array();
80:
81: $i = 0;
82:
83: $lookup = array(
84: 'top' => 'v',
85: 'bottom' => 'v',
86: 'left' => 'h',
87: 'right' => 'h',
88: 'center' => 'c'
89: );
90:
91: foreach ($bits as $bit) {
92: if ($bit === '') {
93: continue;
94: }
95:
96: // test for keyword
97: $lbit = ctype_lower($bit) ? $bit : strtolower($bit);
98: if (isset($lookup[$lbit])) {
99: $status = $lookup[$lbit];
100: if ($status == 'c') {
101: if ($i == 0) {
102: $status = 'ch';
103: } else {
104: $status = 'cv';
105: }
106: }
107: $keywords[$status] = $lbit;
108: $i++;
109: }
110:
111: // test for length
112: $r = $this->length->validate($bit, $config, $context);
113: if ($r !== false) {
114: $measures[] = $r;
115: $i++;
116: }
117:
118: // test for percentage
119: $r = $this->percentage->validate($bit, $config, $context);
120: if ($r !== false) {
121: $measures[] = $r;
122: $i++;
123: }
124: }
125:
126: if (!$i) {
127: return false;
128: } // no valid values were caught
129:
130: $ret = array();
131:
132: // first keyword
133: if ($keywords['h']) {
134: $ret[] = $keywords['h'];
135: } elseif ($keywords['ch']) {
136: $ret[] = $keywords['ch'];
137: $keywords['cv'] = false; // prevent re-use: center = center center
138: } elseif (count($measures)) {
139: $ret[] = array_shift($measures);
140: }
141:
142: if ($keywords['v']) {
143: $ret[] = $keywords['v'];
144: } elseif ($keywords['cv']) {
145: $ret[] = $keywords['cv'];
146: } elseif (count($measures)) {
147: $ret[] = array_shift($measures);
148: }
149:
150: if (empty($ret)) {
151: return false;
152: }
153: return implode(' ', $ret);
154: }
155: }
156:
157: // vim: et sw=4 sts=4
158: