Package io.sf.carte.doc.style.css.nsac
NSAC Base Extension
The base extension is intended to be an easy upgrade path for current SAC users,
providing an API that is very similar to SAC but is able to process modern selectors,
and supports recent syntax and units. The original SAC interfaces are on a package
under the org.w3c hierarchy and cannot be modified directly, so a set of
interfaces that inherit from SAC was created under a new package called
nsac (for Non-Standard Api for Css) in the doc.style.css
hierarchy of this project.
The New Interfaces
The modifications that the new interfaces introduce are basically the following:
LexicalUnit: add new identifiers (constants) and the methodgetCssText(). (see below )Selector: add numeric identifiers for combinatorsSAC_SUBSEQUENT_SIBLING_SELECTORandSAC_COLUMN_COMBINATOR_SELECTOR. Also add theSAC_SCOPE_SELECTORpseudo-selector, intended to be a placeholder for scope in an selector argument (like innot()orhas()).Condition: add numeric identifiers forSAC_BEGINS_ATTRIBUTE_CONDITIONand others, includingSAC_PSEUDO_ELEMENT_CONDITION. Pseudo-elements are handled as conditional selectors with this extension. Also, a newCondition.SAC_SELECTOR_ARGUMENT_CONDITIONidentifier is introduced to support the newArgumentCondition.- New
ArgumentCondition(see below). - New methods added to
AttributeConditionandPositionalCondition(see below).
New Methods and Constants
Interface LexicalUnit
Constants
- Add identifiers for level 3-4 units like
SAC_CAP. - Add
SAC_ELEMENT_REFERENCEfor images by element reference. - For unicode range wildcards, add
SAC_UNICODE_WILDCARD. - Also add the following identifiers for
grid support:
SAC_LEFT_BRACKET,SAC_RIGHT_BRACKETandSAC_FR(frflexible length unit). - Finally, two values that are non-conformant and intended to be used for
compatibility with the Internet Explorer browser:
SAC_COMPAT_IDENTandSAC_COMPAT_PRIOvalues (seeLexicalUnitExtensions).
Method
String getCssText()- Get a parsable representation of the unit. The serialization must only include this lexical unit, ignoring the next units if they exist.
Interface AttributeCondition
boolean hasFlag(Flag)- Check for the given flag. Currently supports
CASE_Ifor theiflag (case insensitivity) andCASE_Sfors.
Interface PositionalCondition
boolean isForwardCondition()- Is this a forward condition? return
trueif this is a forward condition like:nth-child(alsotruefor:only-child),falseotherwise (like in:nth-last-child). boolean isOfType()- Is this an of-type selector? This method only returns
trueif the selector has been explicitly declared to apply to the same type, like in:first-of-typeor:nth-of-type. It should returnfalseotherwise, for example for selectors likediv:nth-child(1 of div)despite being equivalent todiv:first-of-type. This method is possibly the same as the oldPositionalCondition.getType(), but with a potentially different specification. int getFactor()- Get the
An+Bexpression factor (i.e. 'A'). Zero if there is no factor (or no expression). int getOffset()- Get the
An+Bexpression offset (i.e. 'B'). If there is no expression, it must return the positive integer position value (e.g.1for:first-childor:last-child). SelectorList getOfList()- Get the list of selectors that the child list have to match, or
nullif not specified. boolean hasArgument()- Was the selector specified with an argument ?. Serves to tell apart selectors
that have no functional notation from their functional equivalents (like
:first-childand:nth-child(1). boolean hasKeyword()- Get whether the AnB expression was specified as a keyword (like
even).
New Interface ArgumentCondition
String getName()- Get the name of the condition, like
notorhas. SelectorList getSelectors()- Get the selector list to which the condition has to be applied.
Other Changes to Current SAC Usage
Although the changes to SAC described so far are required to handle modern selectors, the NSAC API behaves differently in other aspects:
- The names of pseudo-classes are retrieved with the
AttributeCondition'sgetLocalName()method instead ofgetValue(). This leavesgetValue()to retrieve the pseudo-class argument if there is any, like in:dir(ltr). - The identifier
SAC_ANY_NODE_SELECTORis used for the universal selector, albeit it is still implemented as anElementSelectorwith the*local name. - Margin rules are handled through
startPageandendPage, as nested page rules. Not very elegant, but allows the reuse of the oldDocumentHandlerinterface. - Implementations of
LexicalUnitmust provide a serialization of the value, at least forSAC_IDENTandSAC_RGBCOLORvalues, available throughLexicalUnit2's newgetCssText()method. That serialization should be close to how the value was specified (for example, preserving hex or functional notation in rgb colors) but must parse without errors (except for compatibility values likeSAC_COMPAT_IDENT).
Selector Serialization
Implementations of the selector interfaces are not required to provide a
toString() serialization, although the reference implementation (the
doc.style.css.parser package) does. It is not recommended to use it for
serialization, however, as it may not reflect namespace changes made after the parsing
took place (i.e. changing the namespace prefix). The rule serialization in the
Object Model implementation of css4j does account for that, and it does not use the
selector's toString().
If you combine NSAC with your own Object Model code, you may want to follow the same approach and serialize the selectors yourself.
The Parser Extensions
The previously described base SAC extensions allowed to handle level 4 selectors and
values. However, for the API to be of more general usefulness in real-world usage a few
methods were added to the Parser interface.
Parser Flags
To let the parser be configurable, two methods were added to the Parser
interface:
void setFlag(Flag)
void unsetFlag(Flag)
where Flag is a flag from an enumeration:
STARHACK. WhenSTARHACKis set, the parser will handle asterisk-prefixed property names as accepted names. This hack (that targets old IE browsers) is ubiquitous in present-day websites, and in plain SAC parsers it was producing 'unexpected character' errors because the property names are not valid according to the specification. However, these declarations weren't real mistakes and the style authors wanted them to be there.IEVALUESaccepts values with some IE hacks like IE expressions (progid included), and also values ending with\9and\0. The non-standard values produceLexicalUnit2.SAC_COMPAT_IDENTvalues as a result.IEPRIOaccepts values with the!iepriority hack, and again producesLexicalUnit2.SAC_COMPAT_IDENTvalues.IEPRIOCHARaccepts values with the!important!priority hack, and instead producesLexicalUnit2.SAC_COMPAT_PRIOvalues.
Rule Parsing
The original SAC api includes this method:
void parseRule(InputSource)
The method can be used to parse individual rules, like those supplied to the CSSOM's
CSSStyleSheet.insertRule method:
int insertRule(String, int)
However, when a rule that contains a namespace prefix is parsed, the style sheet may
contain the appropriate CSSNamespaceRule for that prefix, but it is
unclear why/how the Parser instance is going to know about it. To be able
to handle that case, NSAC adds the following method to the Parser
interface:
void parseRule(InputSource, NamespaceMap)
where NamespaceMap is a simple sub-interface that just gives the namespace
URI associated to a prefix:
String getNamespaceURI(String)
LexicalUnit Extensions
Some of the above Internet Explorer compatibility flags require the use of two pseudo-values that do not follow standard CSS syntax:
SAC_COMPAT_IDENTvalues are produced only when theIEVALUESandIEPRIOflags are used, and contain ident-like values.SAC_COMPAT_PRIOvalues are produced by theIEPRIOCHARflag, representing values that its compatible browser interprets as being of!importantpriority.
Caution is advised when using these compatibility pseudo-values, as they may conflict with syntax-conformant values.
Bugs
While this API offers an useful improvement to SAC, that API is old and is showing its age; when it was written, CSS was simpler and smaller than it is today. As this API reuses from SAC as much as possible there are obvious limitations with this approach, like:
DocumentHandler.ignorableAtRuleis a big hammer and not appropriate for today's variety of rules. For example, for@supportsrules it would be better to have specializedstartSupportsandendSupportsmethods than going throughignorableAtRule.- Media queries are unparsed and passed as plain media declarations.
- Combinator selector interfaces were reused, avoiding the creation of a new
interface (like e.g. a plain
CombinatorSelectorinterface). Again, this is not elegant but this API tries to depart minimally from SAC (and this kind of interface reuse was already being done by other SAC implementations).
W3C Copyright Notice
This software includes material derived from SAC (https://www.w3.org/TR/SAC/). Copyright © 1999,2000 W3C® (MIT, INRIA, Keio).
-
ClassDescriptionA condition is applied to a list of selectors that is supplied as an argument to the selector name.Refines SAC's
AttributeConditioninterface.Attribute selector flags.Updates SAC'sConditioninterface.Namespace-related parse exception.Updates SAC'sLexicalUnitinterface.Updates SAC'sParserinterface.NSAC parser flags: theParser2.Flag.STARHACK,Parser2.Flag.IEVALUES,Parser2.Flag.IEPRIOandParser2.Flag.IEPRIOCHARflags are supported.Interface giving access to namespace URI from the prefix.Updates SAC'sPositionalConditioninterface.Updates SAC'sSelectorinterface.