diff --git a/scss.inc.php b/scss.inc.php index 47db2d57..2c50706a 100644 --- a/scss.inc.php +++ b/scss.inc.php @@ -117,7 +117,7 @@ protected function makeOutputBlock($type, $selectors = null) { return $out; } - protected function matchExtendsSingle($single, &$out_origin, &$out_rem) { + protected function matchExtendsSingle($single, &$out_origin) { $counts = array(); foreach ($single as $part) { if (!is_string($part)) return false; // hmm @@ -130,20 +130,30 @@ protected function matchExtendsSingle($single, &$out_origin, &$out_rem) { } } + $out_origin = array(); + $found = false; + foreach ($counts as $idx => $count) { list($target, $origin) = $this->extends[$idx]; + // check count if ($count != count($target)) continue; + // check if target is subset of single if (array_diff(array_intersect($single, $target), $target)) continue; - $out_origin = $origin; - $out_rem = array_diff($single, $target); + $rem = array_diff($single, $target); - return true; + foreach ($origin as $j => $new) { + $origin[$j][count($origin[$j]) - 1] = $this->combineSelectorSingle(end($new), $rem); + } + + $out_origin = array_merge($out_origin, $origin); + + $found = true; } - return false; + return $found; } protected function combineSelectorSingle($base, $other) { @@ -152,7 +162,7 @@ protected function combineSelectorSingle($base, $other) { foreach (array($base, $other) as $single) { foreach ($single as $part) { - if (preg_match('/^[^.#:]/', $part)) { + if (preg_match('/^[^\[.#:]/', $part)) { $tag = $part; } else { $out[] = $part; @@ -171,15 +181,13 @@ protected function matchExtends($selector, &$out, $from = 0, $initial=true) { foreach ($selector as $i => $part) { if ($i < $from) continue; - if ($this->matchExtendsSingle($part, $origin, $rem)) { + if ($this->matchExtendsSingle($part, $origin)) { $before = array_slice($selector, 0, $i); $after = array_slice($selector, $i + 1); foreach ($origin as $new) { - $new[count($new) - 1] = - $this->combineSelectorSingle(end($new), $rem); - $k = 0; + // remove shared parts if ($initial) { foreach ($before as $k => $val) { @@ -317,7 +325,7 @@ protected function flattenSelectorSingle($single) { foreach ($single as $part) { if (empty($joined) || !is_string($part) || - preg_match('/[.:#%]/', $part)) + preg_match('/[\[.:#%]/', $part)) { $joined[] = $part; continue; @@ -1535,7 +1543,7 @@ protected function coerceString($value) { protected function assertList($value) { if ($value[0] != "list") - throw new exception("expecting list"); + throw new Exception("expecting list"); return $value; } @@ -3921,7 +3929,7 @@ public function serve() { if ($this->needsCompile($input, $output)) { try { echo $this->compile($input, $output); - } catch (exception $e) { + } catch (Exception $e) { header('HTTP/1.1 500 Internal Server Error'); echo "Parse error: " . $e->getMessage() . "\n"; } diff --git a/tests/inputs/extends.scss b/tests/inputs/extends.scss index cd6ad526..c6b1bde8 100644 --- a/tests/inputs/extends.scss +++ b/tests/inputs/extends.scss @@ -131,3 +131,43 @@ wassup { color: blue; } } + +// multi-extend + +#something { + color: red; +} + +.x { + @extend #something; +} + +.y { + @extend #something; +} + +// multi-extend with nesting + +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: red; +} +.edit .actions { + button { + float: right; + @extend .btn; + } +} +.edit { + .new { + .actions { + padding: 0; + } + .actions button { + @extend .btn; + } + } +} diff --git a/tests/outputs/extends.css b/tests/outputs/extends.css index 724cb5e8..23d04243 100644 --- a/tests/outputs/extends.css +++ b/tests/outputs/extends.css @@ -16,7 +16,7 @@ hello { .blue, .me { color: purple; } -a:hover, .hoverlink { +a:hover, .hoverlink, #demo .overview .fakelink:hover { text-decoration: underline; } div.hello.world.hmm, pre div.okay.span.world.hmm, pre #butt .umm div.sure.span.world.hmm, #butt .umm pre div.sure.span.world.hmm, code div.okay.span.world.hmm, code #butt .umm div.sure.span.world.hmm, #butt .umm code div.sure.span.world.hmm { @@ -70,3 +70,15 @@ wassup { .foo .wassup { color: blue; } + +#something, .x, .y { + color: red; } + +.btn:hover, .edit .actions button:hover, .edit .new .actions button:hover, .btn:active, .edit .actions button:active, .edit .new .actions button:active, .btn.active, .edit .actions button.active, .edit .new .actions button.active, .btn.disabled, .edit .actions button.disabled, .edit .new .actions button.disabled, .btn[disabled], .edit .actions button[disabled], .edit .new .actions button[disabled] { + color: red; } + +.edit .actions button { + float: right; } + +.edit .new .actions { + padding: 0; }