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