PageRenderTime 51ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Scaffold/Helper/CSS.php

https://github.com/sitepoint/Scaffold
PHP | 378 lines | 168 code | 56 blank | 154 comment | 5 complexity | 318a60a1ac4c3413a2556b13184de799 MD5 | raw file
  1. <?php
  2. /**
  3. * Scaffold_CSS
  4. *
  5. * Helper methods for dealing with CSS
  6. *
  7. * @package Scaffold
  8. * @author Anthony Short <anthonyshort@me.com>
  9. * @copyright 2009-2010 Anthony Short. All rights reserved.
  10. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  11. * @link https://github.com/anthonyshort/csscaffold/master
  12. */
  13. class Scaffold_Helper_CSS
  14. {
  15. /**
  16. * Valid start of a selector
  17. * @var string
  18. */
  19. public static $selector_start = '[0-9A-Za-z\_\#\.\*\:\&\=]';
  20. /**
  21. * Regex for a valid selector
  22. * @var string
  23. */
  24. public static $selector = '[0-9a-zA-Z\_\-\*\&\#\[\]\~\=\|\"\'\^\$\:\>\+\(\)\.\s]';
  25. /**
  26. * Removes single-line comments from a string
  27. * @access public
  28. * @param string
  29. * @return string
  30. */
  31. public static function remove_inline_comments($string)
  32. {
  33. return preg_replace('#($|\s)//.*$#Umsi', '', $string);
  34. }
  35. /**
  36. * Removes line breaks and tabs
  37. * @access public
  38. * @param $string
  39. * @return string
  40. */
  41. public static function remove_newlines($string)
  42. {
  43. return preg_replace('/\n+|\r+|\t+/', '', $string);
  44. }
  45. /**
  46. * Removes css comments
  47. * @access public
  48. * @param $string
  49. * @return string
  50. */
  51. public static function remove_comments($string)
  52. {
  53. return preg_replace('#/\*[^*]*\*+([^/*][^*]*\*+)*/#', '', $string);
  54. }
  55. /**
  56. * Encodes a selector so that it's able to be used in regular expressions
  57. * @access public
  58. * @param $selector
  59. * @return string
  60. */
  61. public static function escape_regex($selector)
  62. {
  63. $selector = preg_quote($selector,'-');
  64. $selector = str_replace('#','\#',$selector);
  65. $selector = preg_replace('/\s+/',"\s+",$selector);
  66. return $selector;
  67. }
  68. // ============================
  69. // = Function Methods =
  70. // ============================
  71. /**
  72. * Finds CSS 'functions'. These are things like url(), embed() etc.
  73. * Handles interior brackets as well by using recursion.
  74. * @access public
  75. * @param $name
  76. * @param $string
  77. * @param $type int Which array to return
  78. * @return array
  79. */
  80. public static function find_functions($name,$string)
  81. {
  82. $return = array();
  83. $regex ="/{$name}(\s*\(\s*((?:(?1)|[^()]+)*)\s*\)\s*)/sx";
  84. if(preg_match_all($regex, $string, $match))
  85. {
  86. foreach($match[0] as $key => $value)
  87. {
  88. $return[$key] = array(
  89. 'string' => $value,
  90. 'param' => $match[2][$key]
  91. );
  92. }
  93. }
  94. return $return;
  95. }
  96. // ============================
  97. // = Ruleset Methods =
  98. // ============================
  99. /**
  100. * Takes a string of a CSS rule:
  101. *
  102. * property:value;
  103. * property:value;
  104. * etc.
  105. *
  106. * And breaks it into an array:
  107. *
  108. * array('property'=>'value');
  109. *
  110. * @param $string
  111. * @return array
  112. */
  113. public static function ruleset_to_array($string)
  114. {
  115. $return = array();
  116. foreach(explode(";", $string) as $value)
  117. {
  118. // Encode any colons inside quotations
  119. if(preg_match_all('/[\'"](.*?\:.*?)[\'"]/',$value,$m) )
  120. {
  121. $value = str_replace($m[0][0],str_replace(':','#COLON#',$m[0][0]),$value);
  122. }
  123. $value = explode(":", $value);
  124. // Make sure it's set
  125. if(isset($value[1]))
  126. {
  127. $return[trim($value[0])] = str_replace('#COLON#', ':', trim($value[1]));
  128. }
  129. }
  130. return $return;
  131. }
  132. // ============================
  133. // = Selector Methods =
  134. // ============================
  135. /**
  136. * Finds selectors which contain a particular property
  137. * @access public
  138. * @param $property string
  139. * @param $css string
  140. * @return array
  141. */
  142. public static function find_selectors_with_property($property,$css)
  143. {
  144. $return = array();
  145. $regex = "/([^{}]*)\s*\{\s*($property|[^}]*[\s\;]$property)\s*:[^}]*}/sx";
  146. if(preg_match_all($regex,$css,$match))
  147. {
  148. foreach($match[0] as $key => $value)
  149. {
  150. $return[$key] = array(
  151. 'string' => $value,
  152. 'selector' => $match[1][$key]
  153. );
  154. }
  155. }
  156. return $return;
  157. }
  158. /**
  159. * Finds a selector and returns it as string
  160. * @access public
  161. * @param $selector string
  162. * @param $string string
  163. * @todo This will break if the selector they try and find is actually part of another selector
  164. */
  165. public static function find_selectors($selector,$string,$escape = true)
  166. {
  167. $selector = ($escape) ? self::escape_regex($selector) : $selector;
  168. $regex = "/(^|[\}\s\;])* ( ($selector) \s*\{[^}]*\} )/sx";
  169. return preg_match_all($regex, $string, $match) ? $match[2] : array();
  170. }
  171. /**
  172. * Check if a selector exists
  173. * @param $name
  174. * @param $string
  175. * @return boolean
  176. */
  177. public static function selector_exists($name,$string)
  178. {
  179. return preg_match('/(^|})\s*'.$name.'\s*\{/', $string) ? true : false;
  180. }
  181. /**
  182. * Checks if a selector is valid
  183. * @param $string
  184. * @return boolean
  185. */
  186. public static function valid_selector($string)
  187. {
  188. return preg_match(self::$_identifier,$string);
  189. }
  190. // ============================
  191. // = Property Methods =
  192. // ============================
  193. /**
  194. * Finds all properties with a particular value
  195. * @access public
  196. * @param $property Regex formatted string for a property
  197. * @param $value Regex formatted string for a value
  198. * @param $css
  199. * @return array
  200. */
  201. public static function find_properties_with_value($property,$value,$css,$escape_value=true)
  202. {
  203. $return = array();
  204. $escaped_property = self::escape_regex($property);
  205. $value = $escape_value ? self::escape_regex($value) : $value;
  206. $regex = "/
  207. \s*
  208. ([^{}]*) (?# selector)
  209. \s*
  210. \{
  211. (?: (?# property is complicated, as we may be first or intermediate - dbackground instance)
  212. [^}]*[\s\;]
  213. |
  214. \s*
  215. )
  216. ($escaped_property\s*)
  217. : (?# property value seperator)
  218. (\s*$value\s*;?)
  219. [^}]* (?# everything after our property of interest)
  220. \} (?# end content)
  221. /sx";
  222. if(preg_match_all($regex,$css,$matches,PREG_SET_ORDER))
  223. {
  224. foreach ( $matches as $key => $match )
  225. {
  226. $return[$key] = array(
  227. 'string' => trim($match[0]),
  228. 'selector' => $match[1],
  229. 'property' => $match[2].':'.$match[3]
  230. );
  231. }
  232. }
  233. return $return;
  234. }
  235. /**
  236. * Removes all instances of a particular property from the css string
  237. * @access public
  238. * @param $property string
  239. * @param $value string
  240. * @param $css string
  241. */
  242. public static function remove_properties_with_value($property,$value,$string,$escape_value=true)
  243. {
  244. # Prepare
  245. $escaped_property = self::escape_regex($property);
  246. $value = $escape_value ? self::escape_regex($value) : $value;
  247. # Generate regex
  248. $regex = "/
  249. (
  250. \{
  251. (?: (?# property is complicated, as we may be first or intermediate - dbackground instance)
  252. \s*
  253. |
  254. [^}]*[\s\;]
  255. )
  256. )
  257. ($escaped_property\s*)
  258. : (?# property value seperator)
  259. (\s*$value\s*;?)
  260. /sx";
  261. # Remove property
  262. $string = preg_replace($regex, '$1', $string);
  263. # Return string
  264. return $string;
  265. }
  266. /**
  267. * Finds all properties within a css string
  268. * @access public
  269. * @param $property string Regex formatted string
  270. * @param $string string
  271. */
  272. public static function find_properties($property,$string)
  273. {
  274. return self::find_properties_with_value($property,'[^;}]*',$string,false);
  275. }
  276. /**
  277. * Removes all instances of a particular property from the css string
  278. * @access public
  279. * @param $property string
  280. * @param $string string
  281. */
  282. public static function remove_properties($property,$string)
  283. {
  284. return self::remove_properties_with_value($property,'[^;}]*',$string,false);
  285. }
  286. // ============================
  287. // = @ Rule Methods =
  288. // ============================
  289. /**
  290. * Finds @groups within the css and returns
  291. * an array with the values, and groups.
  292. * @access public
  293. * @param $name
  294. * @param $string
  295. * @return array
  296. */
  297. public static function find_atrule($name,$string)
  298. {
  299. $name = self::escape_regex($name);
  300. $regex = "/
  301. @{$name} (?# the name to find)
  302. ([^{]*?) (?# atrules params)
  303. \{ (?# start atrule content)
  304. (.*?)
  305. \} (?# end atrule content)
  306. /xs";
  307. $result = preg_match_all($regex, $string, $matches, PREG_SET_ORDER) ? $matches : array();
  308. return $result;
  309. }
  310. /**
  311. * Removes an atrule from a CSS string
  312. * @access public
  313. * @param $name
  314. * @param $css
  315. * @return string
  316. */
  317. public static function remove_atrule($name,$css)
  318. {
  319. $rules = self::find_atrule($name,$css);
  320. return str_replace($rules[0],'',$css);
  321. }
  322. }