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