def is_valid_pseudo_format(self, pseudo_item='', css_class=''): """ Returns True if the CSS class contains a properly formatted pseudo class or element, and False otherwise. **Rules** - The ``css_class`` may end with '-' + pseudo_item. Example prefix: ``color-green-i-hover`` - The ``css_class`` may end with '-' + pseudo_item + '-i'. Example prefix: ``color-green-hover-i`` - The ``css_class`` must be longer than the suffix or suffix + '-i'. :type pseudo_item: str :type css_class: str :param pseudo_item: Either a pseudo class or pseudo element as defined `here <http://www.w3schools.com/css/css_pseudo_classes.asp>`__ :param css_class: This value may or may not be identical to the property_value. :return: *bool* -- Returns True if the CSS class contains the pseudo item, and False otherwise. """ deny_empty_or_whitespace(string=pseudo_item, variable_name='pseudo_item') deny_empty_or_whitespace(string=css_class, variable_name='css_class') suffix = '-' + pseudo_item isuffix = suffix + self.importance_designator if css_class.endswith(suffix) and len(css_class) > len(suffix): # '-i-hover' case return True if css_class.endswith(isuffix) and len(css_class) > len(isuffix): # '-hover-i' case return True return False
def strip_property_abbreviation(self, property_name='', css_class=''): """ Strip property abbreviation from css_class if applicable and return the result. :raises ValueError: If either property_name or css_class are empty or only contain whitespace values. :type property_name: str :type css_class: str :param property_name: Presumed to match a key or value in the ``property_alias_dict`` :param css_class: Initially this value may or may not contain the property_name. :return: (str) -- Returns the encoded property value portion of the css_class. **Examples:** >>> property_parser = ClassPropertyParser() >>> property_parser.strip_property_abbreviation('color', 'c-lime') 'lime' >>> property_parser.strip_property_abbreviation('', 'c-lime') ValueError >>> property_parser.strip_property_abbreviation('color', ' ') ValueError """ deny_empty_or_whitespace(string=css_class, variable_name='css_class') deny_empty_or_whitespace(string=property_name, variable_name='property_name') property_abbreviations = self.get_property_abbreviations(property_name=property_name) for property_abbreviation in property_abbreviations: if css_class.startswith(property_abbreviation): return css_class[len(property_abbreviation):] return css_class
def strip_property_name(property_name='', css_class=''): """ Strip property name from css_class if applicable and return the css_class. :raises ValueError: If either property_name or css_class are empty or only contain whitespace values. :type property_name: str :type css_class: str :param property_name: Presumed to match a key or value in the ``property_alias_dict``. :param css_class: This value may or may not be identical to the property_value. :return: (str) -- Returns the encoded property value portion of the css_class. **Examples:** >>> ClassPropertyParser.strip_property_name('padding', 'padding-1-2-1-2') '1-2-1-2' >>> ClassPropertyParser.strip_property_name('font-weight', 'bold') 'bold' >>> ClassPropertyParser.strip_property_name('', 'padding-1-2-1-2') ValueError >>> ClassPropertyParser.strip_property_name('font-weight', ' ') ValueError """ deny_empty_or_whitespace(string=css_class, variable_name='css_class') deny_empty_or_whitespace(string=property_name, variable_name='property_name') property_name += '-' # Append '-' to property to match the class format. if css_class.startswith(property_name): # Strip property name return css_class[len(property_name):] else: # If it doesn't have a property name ignore it. return css_class
def __init__(self, css_class='', css_property=Property()): deny_empty_or_whitespace(css_class, variable_name='css_class') deny_empty_or_whitespace(css_property.cssText, variable_name='css_property') self.css_class = css_class self.css_property = css_property self.scale_dict = { 'large': 1.043, 'medium': 1.125, 'small': 1.25, } self.scaling_flag = '-s' self.is_scaling = self._is_scaling()
def set_pseudo_element(self, css_class=''): """ Check the pseudo element set for a match. Sets the ``pseudo_element`` if found. Otherwise, returns ''. :raises ValueError: If either property_name or css_class are empty or only contain whitespace values. :type css_class: str :param css_class: This value may or may not be identical to the property_value. :return: None """ deny_empty_or_whitespace(string=css_class, variable_name='css_class') self.pseudo_element = '' for pseudo_element in pseudo_elements: if self.is_valid_pseudo_format(pseudo_element, css_class): self.pseudo_element = pseudo_element
def __init__(self, css_class='', css_property=Property()): deny_empty_or_whitespace(css_class, variable_name='css_class') deny_empty_or_whitespace(css_property.cssText, variable_name='name') self.css_class = css_class self.css_property = css_property self.units = 'em' if use_em else 'px' # Dictionary of Breakpoint Dictionaries {'-only': (), '-down': [1], '-up': [0], } # '-only': ('min-width', 'max-width'), # Lower and Upper Limits of the size. # '-down': ('max-width'), # Upper limit_key of size. # '-up': ('min-width'), # Lower Limit of size. self.breakpoint_dict = { '-xxsmall': {'-only': xxsmall, '-down': xxsmall[1], '-up': xxsmall[0], }, '-xsmall': {'-only': xsmall, '-down': xsmall[1], '-up': xsmall[0], }, '-small': {'-only': small, '-down': small[1], '-up': small[0], }, '-medium': {'-only': medium, '-down': medium[1], '-up': medium[0], }, '-large': {'-only': large, '-down': large[1], '-up': large[0], }, '-xlarge': {'-only': xlarge, '-down': xlarge[1], '-up': xlarge[0], }, '-xxlarge': {'-only': xxlarge, '-down': xxlarge[1], '-up': xxlarge[0], }, '-giant': {'-only': giant, '-down': giant[1], '-up': giant[0], }, '-xgiant': {'-only': xgiant, '-down': xgiant[1], '-up': xgiant[0], }, '-xxgiant': {'-only': xxgiant, '-down': xxgiant[1], '-up': xxgiant[0], }, 'custom': {'-down': None, '-up': None, 'breakpoint': None}, } self.limit_key_set = {'-only', '-down', '-up', } self.breakpoint_key = '' self.limit_key = '' self.is_breakpoint = True # Naively assume True. set_breakpoint_key and set_limit_key can change to False. self.set_breakpoint_key() self.set_limit_key() if self.limit_key in self.limit_key_set and not self.is_breakpoint: # Handle custom breakpoints. self.set_custom_breakpoint_key() self.limit_key_methods = { '-only': self.css_for_only, '-down': self.css_for_down, '-up': self.css_for_up, }
def get_property_value(property_name='', encoded_property_value=''): """ Accepts an encoded_property_value that's been stripped of it's property named and priority Uses CSSPropertyValueParser, and returns a valid css property value or ''. Usage Note: Invalid CSS values can be returned by this method. CSS validation occurs at a later step. :raises ValueError: If either property_name or css_class are empty or only contain whitespace values. :type property_name: str :type encoded_property_value: str :param property_name: Name of CSS property that matches a key in ``property_alias_dict``. :param encoded_property_value: A property value that may or may not contain dashes and underscores. :return: (str) -- An unvalidated / potential CSS property value. **Examples:** >>> property_parser = ClassPropertyParser(set(), False) # Turn OFF unit conversion. >>> property_parser.get_property_value('font-weight', 'bold') # Special case: alias == property value 'bold' >>> property_parser.get_property_value('padding', '1-10-10-5') # Multi-value encoding contains dashes. '1px 10px 10px 5px' >>> property_parser.get_property_value('width', '7_25rem') # Single value contains underscores. '7.25rem' >>> property_parser.get_property_value('margin', '1ap-10xp-3qp-1mp3') # Invalid CSS returned. '1a% 10x% 3q% 1mp3' >>> property_parser.get_property_value('', 'c-lime') ValueError >>> property_parser.get_property_value('color', ' ') ValueError """ deny_empty_or_whitespace(string=property_name, variable_name='property_name') deny_empty_or_whitespace(string=encoded_property_value, variable_name='encoded_property_value') value_parser = CSSPropertyValueParser(property_name=property_name) value = value_parser.decode_property_value(value=encoded_property_value) return value
def strip_pseudo_item(self, css_class=''): """ Strip property name from css_class if applicable and return the css_class. *Note:* This method must be called after ``strip_property_name()``. :raises ValueError: If either pseudo_item or css_class are empty or only contain whitespace values. :type css_class: str :param css_class: _value. :return: (str) -- Returns the encoded property value portion of the css_class. **Examples:** >>> ClassPropertyParser.strip_pseudo_item('hover-padding-1-2-1-2') '1-2-1-2' >>> ClassPropertyParser.strip_pseudo_item('before-bold') 'bold' >>> ClassPropertyParser.strip_pseudo_item('after-1-2-1-2') ValueError >>> ClassPropertyParser.strip_pseudo_item(' ') ValueError """ deny_empty_or_whitespace(string=css_class, variable_name='css_class') self.set_pseudo_class(css_class=css_class) self.set_pseudo_element(css_class=css_class) if self.pseudo_class: # Prepend '-' to property to match the class format. pseudo_item = '-' + self.pseudo_class return css_class.replace(pseudo_item, '') elif self.pseudo_element: pseudo_item = '-' + self.pseudo_element return css_class.replace(pseudo_item, '') else: # No pseudo encoding found. return css_class
def build_media_query(self): """ Returns CSS media queries that scales pixel / em values in response to screen size changes. **Generated CSS for ``font-size-24-s`` minus the inline comments & line breaks**:: // Default size above medium .font-size-24-s { font-size: 24px; } // medium screen font size reduction @media only screen and (max-width: 64.0em) { .font-size-24-s { font-size: 23.0px; } } // medium screen font size reduction @media only screen and (max-width: 45.0em) { .font-size-24-s { font-size: 21.3px; } } // small screen font size reduction @media only screen and (max-width: 30.0em) { .font-size-24-s { font-size: 19.2px; } } **Priority !important -- Generated CSS for ``font-size-24-s-i`` minus the inline comments & line breaks**:: // Default size above the maximum 'medium' width breakpoint. .font-size-24-s-i { font-size: 24px !important; } // medium screen font size reduction @media only screen and (max-width: 64.0em) { .font-size-24-s-i { font-size: 23.0px !important; } } // Apply 'medium' screen font size reduction. @media only screen and (max-width: 45.0em) { .font-size-24-s-i { font-size: 21.3px !important; } } // Apply 'small' screen font size reduction. @media only screen and (max-width: 30.0em) { .font-size-24-s-i { font-size: 19.2px !important; } } :return: (*str*) -- Returns CSS media queries that scales pixel / em values in response to screen size changes. """ if not self.is_scaling: return '' name = self.css_property.name value = self.css_property.value units = ''.join(filter(lambda x: x.isalpha(), value)) # Only keep letters. priority = self.css_property.priority deny_empty_or_whitespace(str(value), variable_name='value') float_value = float(value.replace(units, '')) # Remove units. _max = 1 large_property = Property(name=name, value=value, priority=priority) medium_property = Property(name=name, value=value, priority=priority) small_property = Property(name=name, value=value, priority=priority) large_value = round(float_value / self.scale_dict['large'], 4) # Scale to large screen large_property.value = str(large_value) + units # Add units medium_value = round(float_value / self.scale_dict['medium'], 4) # Scale to medium screen medium_property.value = str(medium_value) + units # Add units small_value = round(float_value / self.scale_dict['small'], 4) # Scale to small screen small_property.value = str(small_value) + units # Add units return ( '.' + self.css_class + ' { ' + self.css_property.cssText + '; }\n\n' + '@media only screen and (max-width: ' + large[_max] + ') {\n' + '\t.' + self.css_class + ' { ' + large_property.cssText + '; }\n' + '}\n\n' + '@media only screen and (max-width: ' + medium[_max] + ') {\n' + '\t.' + self.css_class + ' { ' + medium_property.cssText + '; }\n' + '}\n\n' + '@media only screen and (max-width: ' + small[_max] + ') {\n' + '\t.' + self.css_class + ' { ' + small_property.cssText + '; }\n' + '}\n\n' )
def test_deny_empty_or_whitespace_valid(self): self.assertEqual(deny_empty_or_whitespace(string='valid_string', variable_name='valid_variable'), None)