////////////////////////////// // Import Parser Pieces ////////////////////////////// @import "parsers/query"; @import "parsers/single"; @import "parsers/double"; @import "parsers/triple"; @import "parsers/resolution"; $Memo-Exists: function-exists(memo-get) and function-exists(memo-set); ////////////////////////////// // Breakpoint Function ////////////////////////////// @function breakpoint($query, $contexts...) { $run: true; $return: (); // Grab the Memo Output if Memoization can be a thing @if $Memo-Exists { $return: memo-get(breakpoint, breakpoint $query $contexts); @if $return != null { $run: false; } } @if not $Memo-Exists or $run { // Internal Variables $query-string: ''; $query-fallback: false; $return: (); // Reserve Global Private Breakpoint Context $holder-context: $private-breakpoint-context-holder; $holder-query-count: $private-breakpoint-query-count; // Reset Global Private Breakpoint Context $private-breakpoint-context-holder: () !global; $private-breakpoint-query-count: 0 !global; // Test to see if it's a comma-separated list $or-list: if(list-separator($query) == 'comma', true, false); @if ($or-list == false and breakpoint-get('legacy syntax') == false) { $query-string: breakpoint-parse($query); } @else { $length: length($query); $last: nth($query, $length); $query-fallback: breakpoint-no-query($last); @if ($query-fallback != false) { $length: $length - 1; } @if (breakpoint-get('legacy syntax') == true) { $mq: (); @for $i from 1 through $length { $mq: append($mq, nth($query, $i), comma); } $query-string: breakpoint-parse($mq); } @else { $query-string: ''; @for $i from 1 through $length { $query-string: $query-string + if($i == 1, '', ', ') + breakpoint-parse(nth($query, $i)); } } } $return: ('query': $query-string, 'fallback': $query-fallback, 'context holder': $private-breakpoint-context-holder, 'query count': $private-breakpoint-query-count ); @if length($contexts) > 0 and nth($contexts, 1) != false { @if $query-fallback != false { $context-setter: private-breakpoint-set-context('no-query', $query-fallback); } $context-map: (); @each $context in $contexts { $context-map: map-merge($context-map, ($context: breakpoint-get-context($context))); } $return: map-merge($return, (context: $context-map)); } // Reset Global Private Breakpoint Context $private-breakpoint-context-holder: () !global; $private-breakpoint-query-count: 0 !global; @if $Memo-Exists { $holder: memo-set(breakpoint, breakpoint $query $contexts, $return); } } @return $return; } ////////////////////////////// // General Breakpoint Parser ////////////////////////////// @function breakpoint-parse($query) { // Increase number of 'and' queries $private-breakpoint-query-count: $private-breakpoint-query-count + 1 !global; // Set up Media Type $query-print: ''; $force-all: ((breakpoint-get('force all media type') == true) and (breakpoint-get('default media') == 'all')); $empty-media: true; @if ($force-all == true) or (breakpoint-get('default media') != 'all') { // Force the print of the default media type if (force all is true and default media type is all) or (default media type is not all) $query-print: breakpoint-get('default media'); $empty-media: false; } $query-resolution: false; $query-holder: breakpoint-parse-query($query); // Loop over each parsed out query and write it to $query-print $first: true; @each $feature in $query-holder { $length: length($feature); // Parse a single feature @if ($length == 1) { // Feature is currently a list, grab the actual value $feature: nth($feature, 1); // Media Type must by convention be the first item, so it's safe to flat override $query-print, which right now should only be the default media type @if (breakpoint-is-media($feature)) { @if ($force-all == true) or ($feature != 'all') { // Force the print of the default media type if (force all is true and default media type is all) or (default media type is not all) $query-print: $feature; $empty-media: false; // Set Context $context-setter: private-breakpoint-set-context(media, $query-print); } } @else { $parsed: breakpoint-parse-single($feature, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; $first: false; } } // Parse a double feature @else if ($length == 2) { @if (breakpoint-is-resolution($feature) != false) { $query-resolution: $feature; } @else { $parsed: null; // If it's a string/number pair, // we check to see if one is a single-string value, // then we parse it as a normal double $alpha: nth($feature, 1); $beta: nth($feature, 2); @if breakpoint-single-string($alpha) or breakpoint-single-string($beta) { $parsed: breakpoint-parse-single($alpha, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; $first: false; $parsed: breakpoint-parse-single($beta, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; } @else { $parsed: breakpoint-parse-double($feature, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; $first: false; } } } // Parse a triple feature @else if ($length == 3) { $parsed: breakpoint-parse-triple($feature, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; $first: false; } } @if ($query-resolution != false) { $query-print: breakpoint-build-resolution($query-print, $query-resolution, $empty-media, $first); } // Loop through each feature that's been detected so far and append 'false' to the the value list to increment their counters @each $f, $v in $private-breakpoint-context-holder { $v-holder: $v; $length: length($v-holder); @if length($v-holder) < $private-breakpoint-query-count { @for $i from $length to $private-breakpoint-query-count { @if $f == 'media' { $v-holder: append($v-holder, breakpoint-get('default media')); } @else { $v-holder: append($v-holder, false); } } } $private-breakpoint-context-holder: map-merge($private-breakpoint-context-holder, ($f: $v-holder)) !global; } @return $query-print; }