Package cssutils :: Package css :: Module selectorlist
[hide private]
[frames] | no frames]

Source Code for Module cssutils.css.selectorlist

  1  """SelectorList is a list of CSS Selector objects. 
  2   
  3  TODO 
  4      - remove duplicate Selectors. -> CSSOM canonicalize 
  5   
  6      - ??? CSS2 gives a special meaning to the comma (,) in selectors. 
  7          However, since it is not known if the comma may acquire other 
  8          meanings in future versions of CSS, the whole statement should be 
  9          ignored if there is an error anywhere in the selector, even though 
 10          the rest of the selector may look reasonable in CSS2. 
 11   
 12          Illegal example(s): 
 13   
 14          For example, since the "&" is not a valid token in a CSS2 selector, 
 15          a CSS2 user agent must ignore the whole second line, and not set 
 16          the color of H3 to red: 
 17  """ 
 18  __all__ = ['SelectorList'] 
 19  __docformat__ = 'restructuredtext' 
 20  __version__ = '$Id: selectorlist.py 1174 2008-03-20 17:43:07Z cthedot $' 
 21   
 22  import xml.dom 
 23  import cssutils 
 24  from selector import Selector 
 25   
26 -class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
27 """ 28 (cssutils) a list of Selectors of a CSSStyleRule 29 30 Properties 31 ========== 32 length: of type unsigned long, readonly 33 The number of Selector elements in the list. 34 parentRule: of type CSSRule, readonly 35 The CSS rule that contains this selector list or None if this 36 list is not attached to a CSSRule. 37 selectorText: of type DOMString 38 The textual representation of the selector for the rule set. The 39 implementation may have stripped out insignificant whitespace while 40 parsing the selector. 41 seq: (internal use!) 42 A list of Selector objects 43 wellformed 44 if this selectorlist is wellformed regarding the Selector spec 45 """
46 - def __init__(self, selectorText=None, parentRule=None, 47 readonly=False):
48 """ 49 initializes SelectorList with optional selectorText 50 51 :Parameters: 52 selectorText 53 parsable list of Selectors 54 parentRule 55 the parent CSSRule if available 56 """ 57 super(SelectorList, self).__init__() 58 59 self._parentRule = parentRule 60 61 if selectorText: 62 self.selectorText = selectorText 63 64 self._readonly = readonly
65
66 - def __prepareset(self, newSelector, namespaces=None):
67 "used by appendSelector and __setitem__" 68 if not namespaces: 69 namespaces = {} 70 self._checkReadonly() 71 if not isinstance(newSelector, Selector): 72 newSelector = Selector((newSelector, namespaces), 73 parentList=self) 74 if newSelector.wellformed: 75 newSelector._parent = self # maybe set twice but must be! 76 return newSelector
77
78 - def __setitem__(self, index, newSelector):
79 """ 80 overwrites ListSeq.__setitem__ 81 82 Any duplicate Selectors are **not** removed. 83 """ 84 newSelector = self.__prepareset(newSelector) 85 if newSelector: 86 self.seq[index] = newSelector
87
88 - def append(self, newSelector):
89 "same as appendSelector(newSelector)" 90 self.appendSelector(newSelector)
91 92 length = property(lambda self: len(self), 93 doc="The number of Selector elements in the list.") 94 95
96 - def __getNamespaces(self):
97 "uses children namespaces if not attached to a sheet, else the sheet's ones" 98 try: 99 return self.parentRule.parentStyleSheet.namespaces 100 except AttributeError: 101 namespaces = {} 102 for selector in self.seq: 103 namespaces.update(selector._namespaces) 104 return namespaces
105 106 _namespaces = property(__getNamespaces, doc="""if this SelectorList is 107 attached to a CSSStyleSheet the namespaces of that sheet are mirrored 108 here. While the SelectorList (or parentRule(s) are 109 not attached the namespaces of all children Selectors are used.""") 110 111 parentRule = property(lambda self: self._parentRule, 112 doc="(DOM) The CSS rule that contains this SelectorList or\ 113 None if this SelectorList is not attached to a CSSRule.") 114
115 - def _getSelectorText(self):
116 "returns serialized format" 117 return cssutils.ser.do_css_SelectorList(self)
118
119 - def _setSelectorText(self, selectorText):
120 """ 121 :param selectorText: 122 comma-separated list of selectors or a tuple of 123 (selectorText, dict-of-namespaces) 124 :Exceptions: 125 - `NAMESPACE_ERR`: (Selector) 126 Raised if the specified selector uses an unknown namespace 127 prefix. 128 - `SYNTAX_ERR`: (self) 129 Raised if the specified CSS string value has a syntax error 130 and is unparsable. 131 - `NO_MODIFICATION_ALLOWED_ERR`: (self) 132 Raised if this rule is readonly. 133 """ 134 self._checkReadonly() 135 136 # might be (selectorText, namespaces) 137 selectorText, namespaces = self._splitNamespacesOff(selectorText) 138 try: 139 # use parent's only if available 140 namespaces = self.parentRule.parentStyleSheet.namespaces 141 except AttributeError: 142 pass 143 144 wellformed = True 145 tokenizer = self._tokenize2(selectorText) 146 newseq = [] 147 148 expected = True 149 while True: 150 # find all upto and including next ",", EOF or nothing 151 selectortokens = self._tokensupto2(tokenizer, listseponly=True) 152 if selectortokens: 153 if self._tokenvalue(selectortokens[-1]) == ',': 154 expected = selectortokens.pop() 155 else: 156 expected = None 157 158 selector = Selector((selectortokens, namespaces), 159 parentList=self) 160 if selector.wellformed: 161 newseq.append(selector) 162 else: 163 wellformed = False 164 self._log.error(u'SelectorList: Invalid Selector: %s' % 165 self._valuestr(selectortokens)) 166 else: 167 break 168 169 # post condition 170 if u',' == expected: 171 wellformed = False 172 self._log.error(u'SelectorList: Cannot end with ",": %r' % 173 self._valuestr(selectorText)) 174 elif expected: 175 wellformed = False 176 self._log.error(u'SelectorList: Unknown Syntax: %r' % 177 self._valuestr(selectorText)) 178 if wellformed: 179 self.seq = newseq
180 # for selector in newseq: 181 # self.appendSelector(selector) 182 183 selectorText = property(_getSelectorText, _setSelectorText, 184 doc="""(cssutils) The textual representation of the selector for 185 a rule set.""") 186 187 wellformed = property(lambda self: bool(len(self.seq))) 188
189 - def appendSelector(self, newSelector):
190 """ 191 Append newSelector (a string will be converted to a new 192 Selector). 193 194 :param newSelector: 195 comma-separated list of selectors or a tuple of 196 (selectorText, dict-of-namespaces) 197 :returns: New Selector or None if newSelector is not wellformed. 198 :Exceptions: 199 - `NAMESPACE_ERR`: (self) 200 Raised if the specified selector uses an unknown namespace 201 prefix. 202 - `SYNTAX_ERR`: (self) 203 Raised if the specified CSS string value has a syntax error 204 and is unparsable. 205 - `NO_MODIFICATION_ALLOWED_ERR`: (self) 206 Raised if this rule is readonly. 207 """ 208 self._checkReadonly() 209 210 # might be (selectorText, namespaces) 211 newSelector, namespaces = self._splitNamespacesOff(newSelector) 212 try: 213 # use parent's only if available 214 namespaces = self.parentRule.parentStyleSheet.namespaces 215 except AttributeError: 216 # use already present namespaces plus new given ones 217 _namespaces = self._namespaces 218 _namespaces.update(namespaces) 219 namespaces = _namespaces 220 221 newSelector = self.__prepareset(newSelector, namespaces) 222 if newSelector: 223 seq = self.seq[:] 224 del self.seq[:] 225 for s in seq: 226 if s.selectorText != newSelector.selectorText: 227 self.seq.append(s) 228 self.seq.append(newSelector) 229 return newSelector
230
231 - def __repr__(self):
232 if self._namespaces: 233 st = (self.selectorText, self._namespaces) 234 else: 235 st = self.selectorText 236 return "cssutils.css.%s(selectorText=%r)" % ( 237 self.__class__.__name__, st)
238
239 - def __str__(self):
240 return "<cssutils.css.%s object selectorText=%r _namespaces=%r at 0x%x>" % ( 241 self.__class__.__name__, self.selectorText, self._namespaces, 242 id(self))
243
244 - def _getUsedUris(self):
245 "used by CSSStyleSheet to check if @namespace rules are needed" 246 uris = set() 247 for s in self: 248 uris.update(s._getUsedUris()) 249 return uris
250