mirror-mirror 0.0.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 440d5c08e81aa2644a219d9bb39f6cca9ac5b91e
4
- data.tar.gz: 72a68f59655f65ee4a13c9f812fdbaa8bfca9313
3
+ metadata.gz: 14586345e6e0083164bf05e65d57bc096676491e
4
+ data.tar.gz: 38813d5fea803d5c7b36e1277fd74e9950d22687
5
5
  SHA512:
6
- metadata.gz: 505d1fd16b3e97bbcaa6fe8f763347b2c43952e74c15f8f8769c70ac344d127d5936702365765942b3891c4740499202200a51d190e2b5397cdb86ef7bf78ba8
7
- data.tar.gz: 910d676de83793404e0dd9ef0c93ad5b074baf1e265490a2aaf8c1e2e12f6b83f7368fe14840887e880e92dfdff34c118fc803d6686f7159bb36373fde27ab8b
6
+ metadata.gz: 82e25a14ddac18c555010a536d94ab023eec33f7bc041e2b04a064773667c3bc2a74cad3f946ddafa3694cea3632b5320c1735eed5c7bc3192a7eb2ef974b676
7
+ data.tar.gz: 2bd76bcc6790fea53366a0c315ed6f8e9c4d5eb4549a7d3ff2fadcf366f82d54bf0b77edbff64659dc977a1180db65899abed05760f01a000b782fed195c8f25
@@ -0,0 +1,3 @@
1
+ require 'mirror-mirror'
2
+
3
+ MirrorMirror.activate!
@@ -0,0 +1,195 @@
1
+ require 'mirror-mirror/transformation'
2
+
3
+ module MirrorMirror
4
+ class MirrorVisitor < Sass::Tree::Visitors::Base
5
+ def initialize
6
+ @in_meta_directive = false
7
+ @nested = false
8
+ @enabled = false
9
+ @inline = false
10
+ @options = {}
11
+ @property_transformers = Transformation::PropertyTransformation.instances
12
+ @debug = false
13
+ end
14
+
15
+ def visit_root(root_node)
16
+ # XXX set up defaults from options
17
+ @options = root_node.options
18
+ @enabled = true if @options[:custom] && @options[:custom][:mirror_mirror] == true
19
+ root_node.children = yield
20
+ root_node
21
+ end
22
+
23
+ def visit(node)
24
+ method = "visit_#{node_name node}"
25
+ if self.respond_to?(method, true)
26
+ self.send(method, node) {node.children = visit_children(node)}
27
+ else
28
+ node.children = visit_children(node)
29
+ node
30
+ end
31
+ end
32
+
33
+ def visit_children(parent)
34
+ r = super
35
+ r.flatten!
36
+ r.compact!
37
+ r
38
+ end
39
+
40
+ def visit_rule(rule_node)
41
+ puts "RULE: #{rule_node.resolved_rules}" if @debug
42
+ @nested = true;
43
+ yield
44
+ @nested = false;
45
+ rule_node
46
+ end
47
+
48
+ def visit_prop(prop_node)
49
+ if @in_meta_directive && prop_node.resolved_name == "enabled"
50
+ @enabled = prop_node.resolved_value == "true"
51
+ #if @nested
52
+ #raise Sass::SyntaxError, "Cannot #{@enabled ? 'enable' : 'disable'} mirror flipping in a nested context"
53
+ #end
54
+ puts @enabled ? "ENABLED" : "DISABLED" if @debug
55
+ return prop_node
56
+ end
57
+
58
+ puts "PROPERTY: #{prop_node.resolved_name}" if @debug
59
+ unless @enabled
60
+ return prop_node
61
+ end
62
+
63
+ prop_name = prop_node.resolved_name.downcase
64
+ value = prop_node.resolved_value
65
+ prefix, prop_name = $1, $2 if prop_name =~ /^(\*|_|#|-moz-|-ms-|-webkit-|-o-)(.*)$/
66
+ original_name = prop_name
67
+ original_value = value
68
+ important = nil
69
+
70
+ if value =~ /^(.*[^ ])( *!important *)$/
71
+ value, important = $1, $2
72
+ end
73
+
74
+ property_transformers(prop_name, :name).each do |t|
75
+ prop_name = t.transform_name(prop_name)
76
+ end
77
+
78
+ property_transformers(original_name, :value).each do |t|
79
+ value = t.transform_value(original_name, value)
80
+ end
81
+
82
+ expression = nil
83
+ begin
84
+ property_transformers(original_name, :expression).each do |t|
85
+ expression ||= parsed_value(value, prop_node.line, original_name.size)
86
+ expression = t.transform_expression(original_name, expression)
87
+ end
88
+ rescue Sass::SyntaxError => e
89
+ Sass.logger.warn("Syntax error during mirror flip of `#{original_name}: #{original_value}`: #{e.message}")
90
+ return prop_node
91
+ end
92
+ begin
93
+ value = literalize(expression).to_s(@options) if expression
94
+ rescue => e
95
+ Sass.logger.warn "Failed to stringify the transformation of `#{original_name}: #{original_value}`: #{e.message} (#{expression.class.name})"
96
+ Sass.logger.warn(e.backtrace.join("\n"))
97
+ value = original_value
98
+ end
99
+
100
+ if @debug && prop_node.resolved_name != "#{prefix}#{prop_name}"
101
+ puts "CHANGED name FROM #{prop_node.resolved_name} TO #{prefix}#{prop_name}"
102
+ end
103
+ if @debug && prop_node.resolved_value != value
104
+ puts "CHANGED value FROM #{prop_node.resolved_value} TO #{value}"
105
+ end
106
+ prop_node.resolved_name = "#{prefix}#{prop_name}"
107
+ prop_node.resolved_value = "#{value}#{important}"
108
+ prop_node
109
+ end
110
+
111
+ def visit_directive(directive_node)
112
+ if directive_node.resolved_value.strip == "@-mirror-mirror"
113
+ @in_meta_directive = true
114
+ begin
115
+ yield
116
+ ensure
117
+ @in_meta_directive = false
118
+ end
119
+ nil # remove this node from the output
120
+ elsif directive_node.resolved_value.strip == "@-mirror-mirror no-flip"
121
+ old_enabled = @enabled
122
+ @enabled = false
123
+ begin
124
+ yield
125
+ directive_node.children
126
+ ensure
127
+ @enabled = old_enabled
128
+ end
129
+ elsif directive_node.resolved_value.strip == "@-mirror-mirror inline-flip"
130
+ old_inline = @inline
131
+ old_enabled = @enabled
132
+ @inline = true
133
+ @enabled = true
134
+ begin
135
+ yield
136
+ directive_node.children
137
+ ensure
138
+ @enabled = old_enabled
139
+ @inline = old_inline
140
+ end
141
+ else
142
+ yield
143
+ directive_node
144
+ end
145
+ end
146
+
147
+ protected
148
+
149
+ def property_transformers(name, type)
150
+ @propert_transformers_by_property ||= {}
151
+ @propert_transformers_by_property[name] ||= {}
152
+ @propert_transformers_by_property[name][type] ||= begin
153
+ @property_transformers.select {|t| t.send(:"transform_#{type}?", name)}
154
+ end
155
+ end
156
+
157
+ def parsed_value(value, line, offset)
158
+ slashify(Sass::Script::Parser.new(value, line, offset).parse)
159
+ end
160
+
161
+ def literalize(expression)
162
+ case expression
163
+ when Sass::Script::List
164
+ expression.value.map!{|v| literalize(v) }
165
+ expression
166
+ when Sass::Script::Funcall
167
+ expression.send(:to_literal, expression.args.map {|a| literalize(a) })
168
+ else
169
+ expression
170
+ end
171
+ end
172
+
173
+ def slashify(expression)
174
+ result = _slashify(expression)
175
+ if result.is_a?(Array)
176
+ result = Sass::Script::List.new(result, :space)
177
+ result.options = expression.options
178
+ end
179
+ result
180
+ end
181
+
182
+ def _slashify(expression)
183
+ if expression.is_a?(Sass::Script::List)
184
+ expression.value.map! {|v| _slashify(v) }
185
+ expression.value.flatten!
186
+ elsif expression.is_a?(Sass::Script::Operation)
187
+ operator = Sass::Script::String.new(Sass::Script::Lexer::OPERATORS_REVERSE[expression.operator])
188
+ operator.options = expression.options
189
+ return [_slashify(expression.operand1), operator, _slashify(expression.operand2)]
190
+ end
191
+ expression
192
+ end
193
+
194
+ end
195
+ end
@@ -0,0 +1,5 @@
1
+ module Sass::Script::Functions
2
+ def mirror_mirror_enabled_by_default
3
+ Sass::Script::Bool.new(options[:custom] && options[:custom][:mirror_mirror] == true)
4
+ end
5
+ end
@@ -0,0 +1,62 @@
1
+ require 'mirror-mirror/mirror_visitor'
2
+
3
+ module MirrorMirror
4
+ # Sass should provide hooks for getting access to the AST a various stages of transformation.
5
+ # So that we don't have to monkeypatch it.
6
+ module SassPatch
7
+ def self.included(base)
8
+ if base.respond_to?(:css_tree, true)
9
+ # Sass >= 3.3
10
+ base.send(:alias_method, :css_tree_without_mirror_mirror, :css_tree)
11
+ base.send(:alias_method, :css_tree, :css_tree_with_mirror_mirror)
12
+ else
13
+ # Sass < 3.3
14
+ base.send(:alias_method, :render_without_mirror_mirror, :render)
15
+ base.send(:alias_method, :render, :render_with_mirror_mirror)
16
+ end
17
+ end
18
+
19
+ def css_tree_with_mirror_mirror
20
+ root = css_tree_without_mirror_mirror
21
+ MirrorVisitor.visit(root)
22
+ root
23
+ end
24
+
25
+ def render_with_mirror_mirror
26
+ Sass::Tree::Visitors::CheckNesting.visit(self)
27
+ result = Sass::Tree::Visitors::Perform.visit(self)
28
+ Sass::Tree::Visitors::CheckNesting.visit(result) # Check again to validate mixins
29
+ result, extends = Sass::Tree::Visitors::Cssize.visit(result)
30
+ Sass::Tree::Visitors::Extend.visit(result, extends)
31
+ MirrorVisitor.visit(result)
32
+ result.to_s
33
+ end
34
+ end
35
+
36
+ module CssizePatch
37
+ def visit_directive(directive)
38
+ if directive.resolved_value.start_with?("@-mirror-mirror")
39
+ did_bubble = bubble(directive)
40
+ yield unless did_bubble
41
+ directive
42
+ else
43
+ yield
44
+ directive
45
+ end
46
+ end
47
+ end
48
+
49
+ module DirectiveNodePatch
50
+ def self.included(base)
51
+ base.send(:attr_accessor, :group_end)
52
+ end
53
+
54
+ def bubbles?
55
+ if resolved_value
56
+ resolved_value.start_with?("@-mirror-mirror")
57
+ else
58
+ value.first.start_with?("@-mirror-mirror")
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,114 @@
1
+ module MirrorMirror::Transformation
2
+ class BackgroundPosition < PropertyTransformation
3
+ def transform_expression?(name)
4
+ name == "background" || name == "background-position" || name == "background-position-x"
5
+ end
6
+
7
+ def transform_expression(name, expression)
8
+ for_each_value(expression) do |e|
9
+ if name == "background"
10
+ transform_background(e)
11
+ else
12
+ transform_background_position(e)
13
+ end
14
+ end
15
+ end
16
+
17
+ def transform_background(expression)
18
+ unless expression.is_a?(Sass::Script::List)
19
+ expression = opts(expression.options) do
20
+ Sass::Script::List.new([expression], :space)
21
+ end
22
+ end
23
+ positions = []
24
+ position_indices = []
25
+ expression.value.each_with_index do |v, i|
26
+ if legal_as_background_position?(v)
27
+ positions << v
28
+ position_indices << i
29
+ else
30
+ break if positions.any?
31
+ next
32
+ end
33
+ positions
34
+ end
35
+ return expression unless positions.any?
36
+ if positions.size > 2
37
+ require 'pry'
38
+ binding.pry
39
+ Sass.logger.warn("Line #{expression.line}: malformed background: #{expression.to_sass}")
40
+ return expression
41
+ end
42
+ # tranform the background position elements and replace the position
43
+ # section of the shorthand with it
44
+ transformed = transform_background_position(Sass::Script::List.new(positions, :space))
45
+ position_indices << position_indices.first if position_indices.size < 2
46
+ expression.value[Range.new(*position_indices)] = transformed.value
47
+ expression
48
+ end
49
+
50
+ def transform_background_position(expression)
51
+ unless expression.is_a?(Sass::Script::List)
52
+ expression = opts(expression.options) do
53
+ Sass::Script::List.new([expression], :space)
54
+ end
55
+ end
56
+ if expression.value.size > 2
57
+ # positions with offsets
58
+ expression.value.each_with_index do |e, i|
59
+ next if i % 2 == 1
60
+ expression.value[i] = flip_it(e, i / 2)
61
+ end
62
+ else
63
+ # positions
64
+ expression.value.each_with_index do |e, i|
65
+ expression.value[i] = flip_it(e, i)
66
+ end
67
+ end
68
+ expression
69
+ end
70
+
71
+ ONE_HUNDRED_PERCENT = Sass::Script::Number.new(100, ["%"], [])
72
+
73
+ def flip_it(e, position)
74
+ return e unless e.respond_to?(:value)
75
+ case e
76
+ when Sass::Script::Number
77
+ if position == 0 && e.value == 0
78
+ opts(e.options) { ONE_HUNDRED_PERCENT.dup }
79
+ elsif position == 0 && e.numerator_units.first == "%"
80
+ opts(e.options) { ONE_HUNDRED_PERCENT.minus(e) }
81
+ elsif position == 0
82
+ Sass.logger.warn("Line #{e.line}: Cannot flip background position: #{e}")
83
+ e
84
+ else
85
+ e
86
+ end
87
+ when Sass::Script::String
88
+ case e.value
89
+ when "right"
90
+ e.value.replace("left")
91
+ when "left"
92
+ e.value.replace("right")
93
+ end
94
+ e
95
+ else
96
+ e
97
+ end
98
+ end
99
+
100
+ POSITION_KEYWORDS = Set.new(%w(top bottom left right center))
101
+
102
+ def legal_as_background_position?(e)
103
+ case e
104
+ when Sass::Script::String
105
+ POSITION_KEYWORDS.include?(e.value)
106
+ when Sass::Script::Number
107
+ true
108
+ else
109
+ false
110
+ end
111
+ end
112
+ end
113
+ end
114
+
@@ -0,0 +1,18 @@
1
+ require 'singleton'
2
+
3
+ module MirrorMirror::Transformation
4
+ class Base
5
+ include Singleton
6
+
7
+ def self.inherited(subclass)
8
+ super
9
+ @subclasses ||= []
10
+ @subclasses << subclass
11
+ end
12
+
13
+ def self.instances
14
+ @subclasses.map {|c| c.instance }
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,39 @@
1
+ module MirrorMirror::Transformation
2
+ class BorderRadius < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "border-radius"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ values = value.split(/ +/)
9
+ h_radii = []
10
+ v_radii = []
11
+ has_separator = false
12
+ values.each do |v|
13
+ if v == "/"
14
+ has_separator = true
15
+ next
16
+ end
17
+ if has_separator
18
+ v_radii << v
19
+ else
20
+ h_radii << v
21
+ end
22
+ end
23
+ flip_corners!(h_radii)
24
+ flip_corners!(v_radii)
25
+ values[0...h_radii.size] = h_radii
26
+ if v_radii.any?
27
+ values[(h_radii.size+1)..(h_radii.size+v_radii.size)] = v_radii
28
+ end
29
+ values.join(" ")
30
+ end
31
+
32
+ def flip_corners!(list)
33
+ list[0], list[1] = list[1], list[0] if list.size > 1
34
+ list[2], list[3] = list[3], list[2] if list.size > 3
35
+ nil
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,32 @@
1
+ module MirrorMirror::Transformation
2
+ class BoxShadow < PropertyTransformation
3
+ def transform_expression?(name)
4
+ name == "box-shadow"
5
+ end
6
+
7
+ NEGATIVE_ONE = Sass::Script::Number.new(-1)
8
+
9
+ def transform_expression(name, expression)
10
+ for_each_value(expression) do |e|
11
+ case e
12
+ when Sass::Script::List
13
+ if e.value[0].is_a?(Sass::Script::Number)
14
+ e.value[0] = flip_it(e.value[0])
15
+ end
16
+ when Sass::Script::Number
17
+ e = flip_it(e)
18
+ end
19
+ e
20
+ end
21
+ end
22
+
23
+ def flip_it(expression)
24
+ opts(expression.options) do
25
+ expression.times(NEGATIVE_ONE)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+
32
+
@@ -0,0 +1,17 @@
1
+ module MirrorMirror::Transformation
2
+ class Cursor < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "cursor"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ if value =~ /(n|s)?(e|w)-resize/
9
+ "#{$1}#{$2 == "e" ? "w" : "e"}-resize"
10
+ else
11
+ value
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+
@@ -0,0 +1,18 @@
1
+ module MirrorMirror::Transformation
2
+ class Direction < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "direction"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ case value
9
+ when "ltr"
10
+ "rtl"
11
+ when "rtl"
12
+ "ltr"
13
+ else
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ module MirrorMirror::Transformation
2
+ class DirectionalProperty < PropertyTransformation
3
+ def transform_name?(name)
4
+ name =~ /left|right/
5
+ end
6
+
7
+ def transform_name(name)
8
+ name =~ /^(.*)(left|right)(.*)$/
9
+ "#{$1}#{$2 == "left" ? "right" : "left"}#{$3}"
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,18 @@
1
+ module MirrorMirror::Transformation
2
+ class Float < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "float" || name == "clear"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ case value
9
+ when "left"
10
+ "right"
11
+ when "right"
12
+ "left"
13
+ else
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,84 @@
1
+ require 'set'
2
+ module MirrorMirror::Transformation
3
+ class LinearGradient < PropertyTransformation
4
+ IMAGE_PROPERTIES = Set[
5
+ 'background',
6
+ 'background-image',
7
+ 'border-image',
8
+ 'list-style-image',
9
+ 'list-style',
10
+ 'content'
11
+ ]
12
+ def transform_expression?(name)
13
+ IMAGE_PROPERTIES.include?(name)
14
+ end
15
+
16
+ def transform_expression(name, expression)
17
+ for_each_value(expression) do |e|
18
+ if grad = find_linear_gradient(e)
19
+ if direction?(grad.args[0])
20
+ grad.args[0] = flip(grad.args[0])
21
+ end
22
+ e
23
+ else
24
+ e
25
+ end
26
+ end
27
+ end
28
+
29
+ def find_linear_gradient(expression)
30
+ case expression
31
+ when Sass::Script::List
32
+ expression.value.each do |v|
33
+ grad = find_linear_gradient(v)
34
+ return grad if grad
35
+ end
36
+ nil
37
+ when Sass::Script::Funcall
38
+ expression if expression.name =~ /^(-(moz|webkit|o|ms)-)?(repeating-)?linear-gradient$/
39
+ end
40
+ end
41
+
42
+ def degree?(e)
43
+ e.is_a?(Sass::Script::Number) && e.numerator_units.first == "deg"
44
+ end
45
+
46
+ DIRECTIONAL_KEYWORDS = Set.new(%w(to top left right bottom))
47
+ def directional_keywords?(e)
48
+ (e.is_a?(Sass::Script::List) && DIRECTIONAL_KEYWORDS.include?(e.value.first.value)) ||
49
+ DIRECTIONAL_KEYWORDS.include?(e.value)
50
+ end
51
+
52
+ def direction?(e)
53
+ degree?(e) || directional_keywords?(e)
54
+ end
55
+
56
+ def color_stop?(e)
57
+ e.is_a?(Sass::Script::Color) ||
58
+ (e.is_a?(Sass::Script::List) && e.value.first.is_a?(Sass::Script::Color))
59
+ end
60
+
61
+ S360 = Sass::Script::Number.new(360)
62
+ def flip(direction)
63
+ if degree?(direction)
64
+ opts(direction.options) { S360.minus(direction).mod(S360) }
65
+ else
66
+ case direction
67
+ when Sass::Script::List
68
+ direction.value.map!{|v| flip(v) }
69
+ direction
70
+ when Sass::Script::String
71
+ if direction.value == "left"
72
+ opts(direction.options) { Sass::Script::String.new("right") }
73
+ elsif direction.value == "right"
74
+ opts(direction.options) { Sass::Script::String.new("left") }
75
+ else
76
+ direction
77
+ end
78
+ else
79
+ direction
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,69 @@
1
+ module MirrorMirror::Transformation
2
+ class PropertyTransformation < Base
3
+ # The singleton instances, one for each transformation class
4
+ def self.instances
5
+ super.
6
+ select {|i| i.is_a?(PropertyTransformation) && i.class != PropertyTransformation}
7
+ end
8
+
9
+ # @param name [String] The property name
10
+ # @return [Boolean]
11
+ def transform_name?(name)
12
+ false
13
+ end
14
+
15
+ # @param name [String] The property name
16
+ def transform_name(name)
17
+ name
18
+ end
19
+
20
+ # @param name [String] The property name
21
+ # @return [Boolean]
22
+ def transform_value?(name)
23
+ false
24
+ end
25
+
26
+ # @param name [String] The property name
27
+ # @return [Boolean]
28
+ def transform_expression?(name)
29
+ false
30
+ end
31
+
32
+ # @param property [String] The property whose value is being transformed.
33
+ # Any prefix/hacks should be removed from the property name.
34
+ # @param value [String] The value being transformed.
35
+ # @return [String] A new value for the property
36
+ def transform_value(property, value)
37
+ value
38
+ end
39
+
40
+ # It is safe for this method to mutate the expression that is passed to it.
41
+ #
42
+ # @param property [String] The property whose value is being transformed.
43
+ # Any prefix/hacks should be removed from the property name.
44
+ # @param expression [Sass::Script::Node] The value being transformed.
45
+ # @return [Sass::Script::Node] A new expression for the property
46
+ def transform_expression(property, expression)
47
+ return expression
48
+ end
49
+
50
+ protected
51
+
52
+ def opts(options)
53
+ node = yield
54
+ node.options = options
55
+ node
56
+ end
57
+
58
+ def for_each_value(expression)
59
+ if expression.is_a?(Sass::Script::List) && expression.separator == :comma
60
+ expression.value.map! {|e| yield(e) }
61
+ expression
62
+ else
63
+ yield(expression)
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+
@@ -0,0 +1,25 @@
1
+ require 'set'
2
+ module MirrorMirror::Transformation
3
+ class QuadShorthand < PropertyTransformation
4
+ SHORTHAND_PROPERTIES = Set[
5
+ 'border-color',
6
+ 'border-width',
7
+ 'border-style',
8
+ 'margin',
9
+ 'outline',
10
+ 'padding'
11
+ ]
12
+ def transform_expression?(name)
13
+ SHORTHAND_PROPERTIES.include?(name)
14
+ end
15
+
16
+ def transform_expression(name, expression)
17
+ if expression.is_a?(Sass::Script::List) &&
18
+ expression.separator == :space &&
19
+ expression.value.size == 4
20
+ expression.value[1], expression.value[3] = expression.value[3], expression.value[1]
21
+ end
22
+ expression
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module MirrorMirror::Transformation
2
+ class TextAlign < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "text-align"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ case value
9
+ when "left"
10
+ "right"
11
+ when "right"
12
+ "left"
13
+ else
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,12 @@
1
+ require 'mirror-mirror/transformation/base'
2
+ require 'mirror-mirror/transformation/property_transformation'
3
+ require 'mirror-mirror/transformation/cursor'
4
+ require 'mirror-mirror/transformation/directional_property'
5
+ require 'mirror-mirror/transformation/direction'
6
+ require 'mirror-mirror/transformation/float'
7
+ require 'mirror-mirror/transformation/text_align'
8
+ require 'mirror-mirror/transformation/background_position'
9
+ require 'mirror-mirror/transformation/quad_shorthand'
10
+ require 'mirror-mirror/transformation/box_shadow'
11
+ require 'mirror-mirror/transformation/border_radius'
12
+ require 'mirror-mirror/transformation/linear_gradient'
@@ -1,3 +1,3 @@
1
1
  module MirrorMirror
2
- VERSION = "0.0.1"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/mirror-mirror.rb CHANGED
@@ -1,5 +1,30 @@
1
+ require 'sass'
1
2
  require "mirror-mirror/version"
3
+ require "mirror-mirror/sass_patch"
2
4
 
3
5
  module MirrorMirror
6
+ class << self
7
+ def activate!
8
+ require 'mirror-mirror/sass_functions'
9
+ add_to_load_path!
10
+ Sass::Tree::RootNode.send(:include, SassPatch)
11
+ Sass::Tree::Visitors::Cssize.send(:include, CssizePatch)
12
+ Sass::Tree::DirectiveNode.send(:include, DirectiveNodePatch)
13
+ end
4
14
 
15
+ def add_to_load_path!
16
+ stylesheets_path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'stylesheets'))
17
+ begin
18
+ require 'compass'
19
+ Compass::Frameworks.register('mirror-mirror', :stylesheets_directory => stylesheets_path)
20
+ rescue LoadError
21
+ # compass not found, register on the Sass path via the environment.
22
+ if ENV.has_key?("SASS_PATH")
23
+ ENV["SASS_PATH"] = ENV["SASS_PATH"] + File::PATH_SEPARATOR + stylesheets_path
24
+ else
25
+ ENV["SASS_PATH"] = stylesheets_path
26
+ end
27
+ end
28
+ end
29
+ end
5
30
  end
@@ -0,0 +1,68 @@
1
+ $mirror-mirror-enabled: mirror-mirror-enabled-by-default() !default;
2
+ $mirror-mirror-noflip: false !default;
3
+ $mirror-mirror-default-inline-context: "*[dir=rtl]" !default;
4
+ $mirror-mirror-inline-contexts: ();
5
+
6
+ @function mm-car($list) {
7
+ $new-list: ();
8
+ @for $i from 1 to length($list) {
9
+ $new-list: append($new-list, nth($list, $i));
10
+ }
11
+ @return $new-list;
12
+ }
13
+
14
+ @mixin enable-mirror-flip {
15
+ @if $mirror-mirror-noflip {
16
+ @warn "Enabled flipping in a no-flip. Ignoring.";
17
+ } @else {
18
+ $mirror-mirror-enabled: true;
19
+ @-mirror-mirror {
20
+ enabled: true;
21
+ @content;
22
+ }
23
+ }
24
+ }
25
+
26
+ @mixin disable-mirror-flip {
27
+ @if $mirror-mirror-noflip {
28
+ @warn "Disabled flipping in a no-flip. Ignoring.";
29
+ } @else {
30
+ $mirror-mirror-enabled: false;
31
+ @-mirror-mirror {
32
+ enabled: false;
33
+ @content;
34
+ }
35
+ }
36
+ }
37
+
38
+ @mixin no-flip {
39
+ @if $mirror-mirror-noflip or not $mirror-mirror-enabled {
40
+ @content;
41
+ } @else {
42
+ $mirror-mirror-noflip: true;
43
+ @-mirror-mirror no-flip {
44
+ @content;
45
+ }
46
+ $mirror-mirror-noflip: false;
47
+ }
48
+ }
49
+
50
+ @mixin inline-flip($selector-context: $mirror-mirror-default-inline-context,
51
+ $prepend-context: false) {
52
+ @if $mirror-mirror-enabled {
53
+ // Do nothing if we're in a flipped context already.
54
+ @content;
55
+ } @else {
56
+ @content;
57
+ @-mirror-mirror inline-flip {
58
+ @if not index($mirror-mirror-inline-contexts, $selector-context) {
59
+ $mirror-mirror-inline-contexts: append($mirror-mirror-inline-contexts, $selector-context);
60
+ #{$selector-context} #{if($prepend-context, '&', null)} {
61
+ @content;
62
+ }
63
+ $mirror-mirror-inline-contexts: mm-car($mirror-mirror-inline-contexts);
64
+ }
65
+ }
66
+ }
67
+ }
68
+
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mirror-mirror
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Eppstein
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-21 00:00:00.000000000 Z
11
+ date: 2014-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sass
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -46,13 +60,28 @@ extensions: []
46
60
  extra_rdoc_files: []
47
61
  files:
48
62
  - .gitignore
49
- - Gemfile
50
63
  - LICENSE.txt
51
64
  - README.md
52
- - Rakefile
53
65
  - lib/mirror-mirror.rb
66
+ - lib/mirror-mirror/activate.rb
67
+ - lib/mirror-mirror/mirror_visitor.rb
68
+ - lib/mirror-mirror/sass_functions.rb
69
+ - lib/mirror-mirror/sass_patch.rb
70
+ - lib/mirror-mirror/transformation.rb
71
+ - lib/mirror-mirror/transformation/background_position.rb
72
+ - lib/mirror-mirror/transformation/base.rb
73
+ - lib/mirror-mirror/transformation/border_radius.rb
74
+ - lib/mirror-mirror/transformation/box_shadow.rb
75
+ - lib/mirror-mirror/transformation/cursor.rb
76
+ - lib/mirror-mirror/transformation/direction.rb
77
+ - lib/mirror-mirror/transformation/directional_property.rb
78
+ - lib/mirror-mirror/transformation/float.rb
79
+ - lib/mirror-mirror/transformation/linear_gradient.rb
80
+ - lib/mirror-mirror/transformation/property_transformation.rb
81
+ - lib/mirror-mirror/transformation/quad_shorthand.rb
82
+ - lib/mirror-mirror/transformation/text_align.rb
54
83
  - lib/mirror-mirror/version.rb
55
- - mirror-mirror.gemspec
84
+ - stylesheets/mirror-mirror.scss
56
85
  homepage: ''
57
86
  licenses:
58
87
  - MIT
@@ -78,4 +107,3 @@ signing_key:
78
107
  specification_version: 4
79
108
  summary: Bidirectional CSS transformation utility for Sass.
80
109
  test_files: []
81
- has_rdoc:
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in mirror-mirror.gemspec
4
- gemspec
data/Rakefile DELETED
@@ -1 +0,0 @@
1
- require "bundler/gem_tasks"
@@ -1,23 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'mirror-mirror/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "mirror-mirror"
8
- spec.version = MirrorMirror::VERSION
9
- spec.authors = ["Chris Eppstein"]
10
- spec.email = ["chris@eppsteins.net"]
11
- spec.description = %q{Flip the design of your website along the vertical axis.}
12
- spec.summary = %q{Bidirectional CSS transformation utility for Sass.}
13
- spec.homepage = ""
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
23
- end