using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Collections;
using System.Xml;
#if TEST
using NUnit.Framework;
#endif
namespace SharpVectors.Dom.Css{
/// <summary>
/// The CSSValue interface represents a simple or a complex value. A CSSValue object only occurs in a context of a CSS property
/// </summary>
/// <developer>niklas@protocol7.com</developer>
/// <completed>80</completed>
public class CssValue : ICssValue
{
#region Static members
private static string numberPattern = @"[\-\+]?[0-9]*\.?[0-9]+";
public static string LengthUnitPattern = "(?<lengthUnit>in|cm|mm|px|em|ex|pc|pt|%)?";
public static string AngleUnitPattern = "(?<angleUnit>deg|rad|grad)?";
public static string LengthPattern = @"(?<lengthNumber>" + numberPattern + ")" + LengthUnitPattern;
public static string AnglePattern = @"(?<angleNumber>" + numberPattern + ")" + AngleUnitPattern;
private static string cssPrimValuePattern = @"^(?<primitiveValue>"
+ @"(?<func>(?<funcname>attr|url|counter|rect|rgb)\((?<funcvalue>[^\)]+)\))"
+ @"|(?<length>" + LengthPattern + ")"
+ @"|(?<angle>" + AnglePattern + ")"
+ @"|(?<freqTimeNumber>(?<numberValue2>" + numberPattern + ")(?<unit2>Hz|kHz|in|s|ms|%)?)"
+ @"|(?<string>[""'](?<stringvalue>(.|\n)*?)[""'])"
+ @"|(?<colorIdent>([A-Za-z]+)|(\#[A-Fa-f0-9]{6})|(\#[A-Fa-f0-9]{3}))"
+ @")";
private static Regex reCssPrimitiveValue = new Regex(cssPrimValuePattern + "$");
private static Regex reCssValueList = new Regex(cssPrimValuePattern + @"(\s*,\s*)+$");
/// <summary>
/// Detects what kind of value cssText contains and returns an instance of the correct CssValue class
/// </summary>
/// <param name="cssText">The text to parse for a CSS value</param>
/// <param name="readOnly">Specifies if this instance is read-only</param>
/// <returns>The correct type of CSS value</returns>
static public CssValue GetCssValue(string cssText, bool readOnly)
{
if(cssText == "inherit")
{
// inherit
return new CssValue(CssValueType.Inherit, cssText, readOnly);
}
else
{
Match match = reCssPrimitiveValue.Match(cssText);
if(match.Success)
{
// single primitive value
return CssPrimitiveValue.Create(match, readOnly);
}
match = reCssValueList.Match(cssText);
if(match.Success)
{
// list of primitive values
throw new NotImplementedException("Value lists not implemented");
}
else
{
// custom value
return new CssValue(CssValueType.Custom, cssText, readOnly);
}
}
}
#endregion
#region Constructors
/// <summary>
/// Constructor for CssValue
/// </summary>
/// <param name="type">The type of value</param>
/// <param name="cssText">The entire content of the value</param>
/// <param name="readOnly">Specifies if the instance is read-only</param>
public CssValue(CssValueType type, string cssText, bool readOnly)
{
_cssText = cssText.Trim();
_cssValueType = type;
_readOnly = readOnly;
}
/// <summary>
/// Only for internal use
/// </summary>
protected CssValue()
{
_readOnly = true;
}
#endregion
#region Public methods
public virtual CssValue GetAbsoluteValue(string propertyName, XmlElement elm)
{
return new CssAbsValue(this, propertyName, elm);
}
#endregion
private bool _readOnly;
public virtual bool ReadOnly
{
get
{
return _readOnly;
}
}
#region Implementation of ICssValue
private string _cssText;
/// <summary>
/// A string representation of the current value.
/// </summary>
/// <exception cref="DomException">SYNTAX_ERR: Raised if the specified CSS string value has a syntax error (according to the attached property) or is unparsable.</exception>
/// <exception cref="DomException">INVALID_MODIFICATION_ERR: Raised if the specified CSS string value represents a different type of values than the values allowed by the CSS property</exception>
/// <exception cref="DomException">NO_MODIFICATION_ALLOWED_ERR: Raised if this value is readonly.</exception>
public virtual string CssText
{
get
{
return _cssText;
}
set
{
if(ReadOnly)
{
throw new DomException(DomExceptionType.InvalidModificationErr, "The CssValue is read-only");
}
else
{
_cssText = value;
}
}
}
protected CssValueType _cssValueType;
/// <summary>
/// A code defining the type of the value as defined above
/// </summary>
public virtual CssValueType CssValueType
{
get
{
return _cssValueType;
}
}
#endregion
#region Unit tests
#if TEST
[TestFixture]
public class CssValueTests
{
protected virtual string aCssText
{
get{return "sometext";}
}
protected virtual string anotherCssText
{
get{return "kalle";}
}
protected virtual CssValueType cssValueType
{
get{return CssValueType.Custom;}
}
protected virtual CssValue _getCssValue(string cssText, bool readOnly)
{
return new CssValue(CssValueType.Custom, cssText, readOnly);
}
protected virtual Type Type
{
get{return typeof(CssValue);}
}
[Test]
public void TestCssText()
{
CssValue cssValue = _getCssValue(aCssText, false);
Assert.AreEqual(Type, cssValue.GetType());
}
[Test]
public void TestType()
{
CssValue cssValue = _getCssValue(aCssText, false);
Assert.AreEqual(aCssText, cssValue.CssText);
}
[Test]
public void TestCssTextTrim()
{
CssValue cssValue = _getCssValue(" " + aCssText + " ", false);
Assert.AreEqual(aCssText, cssValue.CssText);
}
[Test]
public void TestCssValueType()
{
CssValue cssValue = _getCssValue(aCssText, false);
Assert.AreEqual(cssValueType, cssValue.CssValueType);
}
[Test]
public virtual void TestCssReadOnly()
{
CssValue cssValue = _getCssValue(aCssText, false);
Assert.AreEqual(false, cssValue.ReadOnly);
cssValue = _getCssValue(aCssText, true);
Assert.AreEqual(true, cssValue.ReadOnly);
}
[Test]
public void TestCssTextReadWrite()
{
CssValue cssValue = _getCssValue(aCssText, false);
cssValue.CssText = anotherCssText;
Assert.AreEqual(anotherCssText, cssValue.CssText);
}
[Test]
[ExpectedException(typeof(DomException))]
public virtual void TestCssTextReadOnly()
{
CssValue cssValue = _getCssValue(aCssText, true);
cssValue.CssText = anotherCssText;
}
[Test]
public void CssValueInheritTest()
{
CssValue cssValue = new CssValue(CssValueType.Inherit, "inherit", false);
Assert.AreEqual("inherit", cssValue.CssText);
Assert.AreEqual(CssValueType.Inherit, cssValue.CssValueType);
}
[Test]
public void CssValueCustomTest()
{
CssValue cssValue = new CssValue(CssValueType.Custom, "some custom value ", false);
Assert.AreEqual("some custom value", cssValue.CssText);
Assert.AreEqual(CssValueType.Custom, cssValue.CssValueType);
}
}
#endif
#endregion
}
}
|