Class: R2::Swapper
- Inherits:
-
Object
- Object
- R2::Swapper
- Defined in:
- lib/r2.rb
Overview
Reuable class for CSS alterations
Constant Summary collapse
- PROPERTY_MAP =
{ 'margin-left' => 'margin-right', 'margin-right' => 'margin-left', 'padding-left' => 'padding-right', 'padding-right' => 'padding-left', 'border-left' => 'border-right', 'border-right' => 'border-left', 'border-left-width' => 'border-right-width', 'border-right-width' => 'border-left-width', 'border-radius-bottomleft' => 'border-radius-bottomright', 'border-radius-bottomright' => 'border-radius-bottomleft', 'border-radius-topleft' => 'border-radius-topright', 'border-radius-topright' => 'border-radius-topleft', '-moz-border-radius-bottomright' => '-moz-border-radius-bottomleft', '-moz-border-radius-bottomleft' => '-moz-border-radius-bottomright', '-moz-border-radius-topright' => '-moz-border-radius-topleft', '-moz-border-radius-topleft' => '-moz-border-radius-topright', '-webkit-border-top-right-radius' => '-webkit-border-top-left-radius', '-webkit-border-top-left-radius' => '-webkit-border-top-right-radius', '-webkit-border-bottom-right-radius' => '-webkit-border-bottom-left-radius', '-webkit-border-bottom-left-radius' => '-webkit-border-bottom-right-radius', 'left' => 'right', 'right' => 'left' }
- VALUE_PROCS =
{ 'padding' => lambda {|obj,val| obj.quad_swap(val) }, 'margin' => lambda {|obj,val| obj.quad_swap(val) }, 'border-radius' => lambda {|obj,val| obj.border_radius_swap(val) }, '-moz-border-radius' => lambda {|obj,val| obj.border_radius_swap(val) }, '-webkit-border-radius' => lambda {|obj,val| obj.border_radius_swap(val) }, 'text-align' => lambda {|obj,val| obj.side_swap(val) }, 'float' => lambda {|obj,val| obj.side_swap(val) }, 'box-shadow' => lambda {|obj,val| obj.shadow_swap(val) }, '-webkit-box-shadow' => lambda {|obj,val| obj.shadow_swap(val) }, '-moz-box-shadow' => lambda {|obj,val| obj.shadow_swap(val) }, 'direction' => lambda {|obj,val| obj.direction_swap(val) }, 'clear' => lambda {|obj,val| obj.side_swap(val) }, 'background-position' => lambda {|obj,val| obj.background_position_swap(val) }, 'background' => lambda {|obj,val| obj.background_swap(val) }, }
Instance Method Summary collapse
- #append_important(is_important, &block) ⇒ Object
-
#background_position_swap(val) ⇒ Object
Given a background-position such as
left center
or0% 50%
return the opposing value e.gright center
or100% 50%
. -
#background_swap(val) ⇒ Object
Given the short-hand background: definition attempt to convert the direction.
-
#border_radius_swap(css_value) ⇒ Object
Border radius uses top-left, top-right, bottom-left, bottom-right, so all values need to be swapped.
-
#declaration_swap(decl) ⇒ Object
Given a single CSS declaration rule (e.g.
padding-left: 4px
) return the opposing rule (so,padding-right:4px;
in this example). -
#direction_swap(val) ⇒ Object
Given a value of
rtl
orltr
return the opposing value. - #extract_important(css) ⇒ Object
-
#minimize(css) ⇒ Object
Minimize the provided CSS by removing comments, and extra specs.
-
#quad_swap(css_value) ⇒ Object
Given a 4-argument CSS declaration value (like that of
padding
ormargin
) return the opposing value. -
#r2(original_css) ⇒ Object
Given a String of CSS perform the full directionality change.
-
#shadow_swap(val) ⇒ Object
Given the 2-6 variable declaration for box-shadow convert the direction.
-
#side_swap(val) ⇒ Object
Given a value of
right
orleft
return the opposing value.
Instance Method Details
#append_important(is_important, &block) ⇒ Object
273 274 275 276 |
# File 'lib/r2.rb', line 273 def append_important(is_important, &block) css_value = yield css_value + (is_important ? " #{IMPORTANT_DECLARATION}" : '') end |
#background_position_swap(val) ⇒ Object
Given a background-position such as left center
or 0% 50%
return the opposing value e.g right center
or 100% 50%
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/r2.rb', line 244 def background_position_swap(val) if val =~ /left/ val.gsub!('left', 'right') elsif val =~ /right/ val.gsub!('right', 'left') end points = val.strip.split(/\s+/) # If first point is a percentage-value if match = points[0].match(/(\d+)%/) inv = 100 - match[1].to_i # 30% => 70% (100 - x) val = ["#{inv}%", points[1]].compact.join(' ') end # If first point is a unit-value if match = points[0].match(/^(-?\d+[a-z]{2,3})/) val = ["right", match[1], points[1] || "center"].compact.join(' ') end val end |
#background_swap(val) ⇒ Object
Given the short-hand background: definition attempt to convert the direction.
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/r2.rb', line 192 def background_swap(val) parts = val.split(/ /) checked = [] skip = false parts.each_index do |i| p = parts[i] n = parts[i+1] if skip skip = false next end if p.match(/left|right|\d+%/) checked << background_position_swap("#{p} #{n}") skip = true else checked << side_swap(p) end end checked.flatten.join(' ') end |
#border_radius_swap(css_value) ⇒ Object
Border radius uses top-left, top-right, bottom-left, bottom-right, so all values need to be swapped. Additionally, two and three value border-radius declarations need to be swapped as well. Vertical radius, specified with a /, should be left alone.
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/r2.rb', line 221 def border_radius_swap(css_value) # 1px 2px 3px 4px => 1px 4px 3px 2px points_str, is_important = extract_important(css_value) points = points_str.to_s.split(/\s+/) append_important(is_important) do if points && points.length > 1 && !points_str.to_s.include?('/') case points.length when 4 [points[1], points[0], points[3], points[2]].join(' ') when 3 [points[1], points[0], points[1], points[2]].join(' ') when 2 [points[1], points[0]].join(' ') else points_str end else points_str end end end |
#declaration_swap(decl) ⇒ Object
Given a single CSS declaration rule (e.g. padding-left: 4px
) return the opposing rule (so, padding-right:4px;
in this example)
131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/r2.rb', line 131 def declaration_swap(decl) return '' unless decl matched = decl.match(/([^:]+):(.+)$/) return '' unless matched property = matched[1] value = matched[2] property = PROPERTY_MAP[property] if PROPERTY_MAP.has_key?(property) value = VALUE_PROCS[property].call(self, value) if VALUE_PROCS.has_key?(property) return property + ':' + value + ';' end |
#direction_swap(val) ⇒ Object
Given a value of rtl
or ltr
return the opposing value. All other arguments are ignored and returned unmolested.
147 148 149 150 151 152 153 154 155 |
# File 'lib/r2.rb', line 147 def direction_swap(val) if val == "rtl" "ltr" elsif val == "ltr" "rtl" else val end end |
#extract_important(css) ⇒ Object
268 269 270 271 |
# File 'lib/r2.rb', line 268 def extract_important(css) is_important = css =~ /#{IMPORTANT_DECLARATION}/ return css.sub(/ #{IMPORTANT_DECLARATION}/, ''), is_important end |
#minimize(css) ⇒ Object
Minimize the provided CSS by removing comments, and extra specs
119 120 121 122 123 124 125 126 127 128 |
# File 'lib/r2.rb', line 119 def minimize(css) return '' unless css css.gsub(/\/\*\s*no-r2\s*\*\//, SKIP_TOKEN). # special skip comment gsub(/\/\*[\s\S]+?\*\//, ''). # comments gsub(/[\n\r]+/, ' '). # line breaks and carriage returns gsub(/\s*([:;,\{\}])\s*/, '\1'). # space between selectors, declarations, properties and values gsub(/\s+/, ' '). # replace multiple spaces with single spaces gsub(/(\A\s+|\s+\z)/, '') # leading or trailing spaces end |
#quad_swap(css_value) ⇒ Object
Given a 4-argument CSS declaration value (like that of padding
or margin
) return the opposing value. The opposing value swaps the left and right but not the top or bottom. Any unrecognized argument is returned unmolested (for example, 2-argument values)
171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/r2.rb', line 171 def quad_swap(css_value) points_str, is_important = extract_important(css_value) # 1px 2px 3px 4px => 1px 4px 3px 2px points = points_str.to_s.split(/\s+/) append_important(is_important) do if points && points.length == 4 [points[0], points[3], points[2], points[1]].join(' ') else points_str end end end |
#r2(original_css) ⇒ Object
Given a String of CSS perform the full directionality change
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/r2.rb', line 76 def r2(original_css) css = minimize(original_css) result = css.gsub(/([^\{\}]+[^\}]|[\}])+?/) do |rule| # +rule+ can represent a selector (".foo {"), the closing "}" for a selector, or the complete # body of a a selector if rule.match(/[\{\}]/) # it is a selector with "{" or a closing "}", insert as it is. This is # things like ".foo {" and its matching "}" rule_str = rule elsif rule.match(/#{SKIP_TOKEN}/) # A body that is being skipped rule_str = rule.sub(SKIP_TOKEN, '') else # It is a declaration body, like "padding-left:4px;margin-left:5px;" rule_str = "" # Split up the individual rules in the body and process each swap. To handle the # possible ";" in the url() definitions, like # url("data;base64") and url("data:image/svg+xml;charset=...") # a state machine is constructed. url_rule = nil rule.split(/;/).each do |part| # A rule body that contains a "url(" and a ";" before the closing ")" if part.match(/url\([^\)]+$/) url_rule = part elsif url_rule != nil url_rule << ";" + part if part.match(/\)( |$)/) rule_str << declaration_swap(url_rule) url_rule = nil end else rule_str << declaration_swap(part) end end end rule_str end return result end |
#shadow_swap(val) ⇒ Object
Given the 2-6 variable declaration for box-shadow convert the direction. Conversion requires inverting the horizontal measure only.
187 188 189 |
# File 'lib/r2.rb', line 187 def shadow_swap(val) ShadowFlipper::flip(val) end |
#side_swap(val) ⇒ Object
Given a value of right
or left
return the opposing value. All other arguments are ignored and returned unmolested.
158 159 160 161 162 163 164 165 166 |
# File 'lib/r2.rb', line 158 def side_swap(val) if val == "right" "left" elsif val == "left" "right" else val end end |