BackgroundPosition.php 3.6 KB

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