/* BasicPseudoClassDefs.java
Purpose:
Description:
History:
Mar 20, 2012 Created by pao
Copyright (C) 2011 Potix Corporation. All Rights Reserved.
*/
// ported from zk 6.0.0
// original package: org.zkoss.zk.ui.select
package org.zkoss.zats.common.select.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* The default set of pseudo classes in Selector.
* @since 6.0.0
* @author simonpai
*/
public class BasicPseudoClassDefs
{
private final static Map<String, PseudoClassDef> _defs = new HashMap<String, PseudoClassDef>();
static
{
// :root
_defs.put("root", new PseudoClassDef()
{
public boolean accept(ComponentMatchCtx ctx, String... parameters)
{
if(parameters.length > 0)
return false;
return ctx.getComponent().getParent() == null;
}
});
// :first-child
_defs.put("first-child", new PseudoClassDef()
{
public boolean accept(ComponentMatchCtx ctx, String... parameters)
{
if(parameters.length > 0)
return false;
return ctx.getComponentChildIndex() == 0;
}
});
// :last-child
_defs.put("last-child", new PseudoClassDef()
{
public boolean accept(ComponentMatchCtx ctx, String... parameters)
{
if(parameters.length > 0)
return false;
return ctx.getComponentChildIndex() + 1 == ctx.getComponentSiblingSize();
}
});
// :only-child
_defs.put("only-child", new PseudoClassDef()
{
public boolean accept(ComponentMatchCtx ctx, String... parameters)
{
if(parameters.length > 0)
return false;
return ctx.getComponentSiblingSize() == 1;
}
});
// :empty
_defs.put("empty", new PseudoClassDef()
{
public boolean accept(ComponentMatchCtx ctx, String... parameters)
{
if(parameters.length > 0)
return false;
return ctx.getComponent().getChildren().isEmpty();
}
});
// :nth-child(n)
_defs.put("nth-child", new PseudoClassDef()
{
public boolean accept(ComponentMatchCtx ctx, String... parameters)
{
return parameters.length == 1 && acceptNthPattern(ctx.getComponentChildIndex() + 1, parameters[0]);
}
});
// :nth-last-child(n)
_defs.put("nth-last-child", new PseudoClassDef()
{
public boolean accept(ComponentMatchCtx ctx, String... parameters)
{
return parameters.length == 1 && acceptNthPattern(ctx.getComponentSiblingSize() - ctx.getComponentChildIndex(), parameters[0]);
}
});
}
/**
* Returns the pseudo class definition associated with the given name
* @param name the pseudo class name
* @return a pseudo class definition
*/
public static PseudoClassDef getDefinition(String name)
{
return _defs.get(name);
}
// helper //
private static boolean acceptNthPattern(int index, String pattern)
{
return "odd".equals(pattern) && index % 2 == 1 || "even".equals(pattern) && index % 2 == 0 || new NthChildPattern(pattern).accept(index);
}
private static class NthChildPattern
{
private final int _preNum;
private final int _postNum;
private final boolean _valid;
private NthChildPattern(String pattern)
{
int npos = pattern.indexOf('n');
String preStr = npos < 0 ? "" : pattern.substring(0, npos);
String postStr = npos < 0 ? pattern : pattern.substring(npos + 1);
_valid = Pattern.matches("(?:\\+|-)?\\d*", preStr) && Pattern.matches("(?:(?:\\+|-)?\\d+)?", postStr);
_preNum = _valid ? value(preStr, npos < 0 ? 0 : 1) : -1;
_postNum = _valid ? value(postStr, 0) : -1;
}
private boolean accept(int index)
{
if(!_valid)
return false;
if(_preNum == 0)
return index == _postNum;
int diff = index - _postNum;
return diff % _preNum == 0 && diff / _preNum >= 0;
}
private int value(String str, int defValue)
{
if(str.length() <= 0)
return defValue;
char p = str.charAt(0);
String s = (p == '+' || p == '-') ? str.substring(1) : str;
return (p == '-' ? -1 : 1) * (s.length() <= 0 ? defValue : Integer.valueOf(s));
}
}
}