canvas::Element: setter/getter for HTML5 style data-* properties.
This commit is contained in:
@@ -24,3 +24,8 @@ set(SOURCES
|
|||||||
|
|
||||||
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
|
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
|
||||||
simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}")
|
simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}")
|
||||||
|
|
||||||
|
add_boost_test(canvas_element
|
||||||
|
SOURCES canvas_element_test.cpp
|
||||||
|
LIBRARIES ${TEST_LIBS}
|
||||||
|
)
|
||||||
@@ -437,7 +437,8 @@ namespace canvas
|
|||||||
else if( boost::starts_with(name, "blend-") )
|
else if( boost::starts_with(name, "blend-") )
|
||||||
return (void)(_attributes_dirty |= BLEND_FUNC);
|
return (void)(_attributes_dirty |= BLEND_FUNC);
|
||||||
}
|
}
|
||||||
else if( parent->getParent() == _node
|
else if( parent
|
||||||
|
&& parent->getParent() == _node
|
||||||
&& parent->getNameString() == NAME_TRANSFORM )
|
&& parent->getNameString() == NAME_TRANSFORM )
|
||||||
{
|
{
|
||||||
_attributes_dirty |= TRANSFORM;
|
_attributes_dirty |= TRANSFORM;
|
||||||
@@ -634,6 +635,74 @@ namespace canvas
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static const std::string DATA_PREFIX("data-");
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::string Element::dataPropToAttrName(const std::string& name)
|
||||||
|
{
|
||||||
|
// http://www.w3.org/TR/html5/dom.html#attr-data-*
|
||||||
|
//
|
||||||
|
// 3. Insert the string data- at the front of name.
|
||||||
|
|
||||||
|
std::string attr_name;
|
||||||
|
for( std::string::const_iterator cur = name.begin();
|
||||||
|
cur != name.end();
|
||||||
|
++cur )
|
||||||
|
{
|
||||||
|
// If name contains a "-" (U+002D) character followed by a lowercase ASCII
|
||||||
|
// letter, throw a SyntaxError exception and abort these steps.
|
||||||
|
if( *cur == '-' )
|
||||||
|
{
|
||||||
|
std::string::const_iterator next = cur + 1;
|
||||||
|
if( next != name.end() && islower(*next) )
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each uppercase ASCII letter in name, insert a "-" (U+002D)
|
||||||
|
// character before the character and replace the character with the same
|
||||||
|
// character converted to ASCII lowercase.
|
||||||
|
if( isupper(*cur) )
|
||||||
|
{
|
||||||
|
attr_name.push_back('-');
|
||||||
|
attr_name.push_back( tolower(*cur) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
attr_name.push_back( *cur );
|
||||||
|
}
|
||||||
|
return DATA_PREFIX + attr_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::string Element::attrToDataPropName(const std::string& name)
|
||||||
|
{
|
||||||
|
// http://www.w3.org/TR/html5/dom.html#attr-data-*
|
||||||
|
//
|
||||||
|
// For each "-" (U+002D) character in the name that is followed by a
|
||||||
|
// lowercase ASCII letter, remove the "-" (U+002D) character and replace the
|
||||||
|
// character that followed it by the same character converted to ASCII
|
||||||
|
// uppercase.
|
||||||
|
|
||||||
|
if( !boost::starts_with(name, DATA_PREFIX) )
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::string data_name;
|
||||||
|
for( std::string::const_iterator cur = name.begin() + DATA_PREFIX.length();
|
||||||
|
cur != name.end();
|
||||||
|
++cur )
|
||||||
|
{
|
||||||
|
std::string::const_iterator next = cur + 1;
|
||||||
|
if( *cur == '-' && next != name.end() && islower(*next) )
|
||||||
|
{
|
||||||
|
data_name.push_back( toupper(*next) );
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
data_name.push_back(*cur);
|
||||||
|
}
|
||||||
|
return data_name;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
Element::StyleSetters Element::_style_setters;
|
Element::StyleSetters Element::_style_setters;
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,30 @@ namespace canvas
|
|||||||
bool addEventListener(const std::string& type, const EventListener& cb);
|
bool addEventListener(const std::string& type, const EventListener& cb);
|
||||||
virtual void clearEventListener();
|
virtual void clearEventListener();
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void setDataProp( const std::string& name,
|
||||||
|
const T& val )
|
||||||
|
{
|
||||||
|
const std::string& attr = dataPropToAttrName(name);
|
||||||
|
if( !attr.empty() )
|
||||||
|
set<T>(attr, val);
|
||||||
|
else
|
||||||
|
SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T getDataProp( const std::string& name,
|
||||||
|
const T& def = T() )
|
||||||
|
{
|
||||||
|
const std::string& attr = dataPropToAttrName(name);
|
||||||
|
if( !attr.empty() )
|
||||||
|
return get<T>(attr, def);
|
||||||
|
else
|
||||||
|
SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
|
||||||
|
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool accept(EventVisitor& visitor);
|
virtual bool accept(EventVisitor& visitor);
|
||||||
virtual bool ascend(EventVisitor& visitor);
|
virtual bool ascend(EventVisitor& visitor);
|
||||||
virtual bool traverse(EventVisitor& visitor);
|
virtual bool traverse(EventVisitor& visitor);
|
||||||
@@ -195,12 +219,15 @@ namespace canvas
|
|||||||
ElementPtr
|
ElementPtr
|
||||||
>::type create( const CanvasWeakPtr& canvas,
|
>::type create( const CanvasWeakPtr& canvas,
|
||||||
const SGPropertyNode_ptr& node,
|
const SGPropertyNode_ptr& node,
|
||||||
const Style& style,
|
const Style& style = Style(),
|
||||||
Element* parent )
|
Element* parent = NULL )
|
||||||
{
|
{
|
||||||
return ElementPtr( new Derived(canvas, node, style, parent) );
|
return ElementPtr( new Derived(canvas, node, style, parent) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string dataPropToAttrName(const std::string& name);
|
||||||
|
static std::string attrToDataPropName(const std::string& name);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
enum Attributes
|
enum Attributes
|
||||||
|
|||||||
@@ -320,10 +320,12 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Group::childChanged(SGPropertyNode* node)
|
void Group::childChanged(SGPropertyNode* node)
|
||||||
{
|
{
|
||||||
if( node->getParent()->getParent() == _node
|
SGPropertyNode* parent = node->getParent();
|
||||||
|
SGPropertyNode* grand_parent = parent ? parent->getParent() : NULL;
|
||||||
|
|
||||||
|
if( grand_parent == _node
|
||||||
&& node->getNameString() == "z-index" )
|
&& node->getNameString() == "z-index" )
|
||||||
return handleZIndexChanged( getChild(node->getParent()),
|
return handleZIndexChanged(getChild(parent), node->getIntValue());
|
||||||
node->getIntValue() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|||||||
54
simgear/canvas/elements/canvas_element_test.cpp
Normal file
54
simgear/canvas/elements/canvas_element_test.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/// Unit tests for canvas::Element
|
||||||
|
#define BOOST_TEST_MODULE canvas
|
||||||
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
|
#include "CanvasElement.hxx"
|
||||||
|
#include "CanvasGroup.hxx"
|
||||||
|
|
||||||
|
namespace sc = simgear::canvas;
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( attr_data )
|
||||||
|
{
|
||||||
|
// http://www.w3.org/TR/html5/dom.html#attr-data-*
|
||||||
|
|
||||||
|
#define SG_CHECK_ATTR2PROP(attr, prop)\
|
||||||
|
BOOST_CHECK_EQUAL(sc::Element::attrToDataPropName(attr), prop)
|
||||||
|
|
||||||
|
// If name starts with "data-", for each "-" (U+002D) character in the name
|
||||||
|
// that is followed by a lowercase ASCII letter, remove the "-" (U+002D)
|
||||||
|
// character and replace the character that followed it by the same character
|
||||||
|
// converted to ASCII uppercase.
|
||||||
|
|
||||||
|
SG_CHECK_ATTR2PROP("no-data", "");
|
||||||
|
SG_CHECK_ATTR2PROP("data-blub", "blub");
|
||||||
|
SG_CHECK_ATTR2PROP("data-blub-x-y", "blubXY");
|
||||||
|
SG_CHECK_ATTR2PROP("data-blub-x-y-", "blubXY-");
|
||||||
|
|
||||||
|
#undef SG_CHECK_ATTR2PROP
|
||||||
|
|
||||||
|
#define SG_CHECK_PROP2ATTR(prop, attr)\
|
||||||
|
BOOST_CHECK_EQUAL(sc::Element::dataPropToAttrName(prop), attr)
|
||||||
|
|
||||||
|
// If name contains a "-" (U+002D) character followed by a lowercase ASCII
|
||||||
|
// letter, throw a SyntaxError exception (empty string) and abort these steps.
|
||||||
|
// For each uppercase ASCII letter in name, insert a "-" (U+002D) character
|
||||||
|
// before the character and replace the character with the same character
|
||||||
|
// converted to ASCII lowercase.
|
||||||
|
// Insert the string "data-" at the front of name.
|
||||||
|
|
||||||
|
SG_CHECK_PROP2ATTR("test", "data-test");
|
||||||
|
SG_CHECK_PROP2ATTR("testIt", "data-test-it");
|
||||||
|
SG_CHECK_PROP2ATTR("testIt-Hyphen", "data-test-it--hyphen");
|
||||||
|
SG_CHECK_PROP2ATTR("-test", "");
|
||||||
|
SG_CHECK_PROP2ATTR("test-", "data-test-");
|
||||||
|
|
||||||
|
#undef SG_CHECK_PROP2ATTR
|
||||||
|
|
||||||
|
SGPropertyNode_ptr node = new SGPropertyNode;
|
||||||
|
sc::ElementPtr el =
|
||||||
|
sc::Element::create<sc::Group>(sc::CanvasWeakPtr(), node);
|
||||||
|
|
||||||
|
el->setDataProp("myData", 3);
|
||||||
|
BOOST_CHECK_EQUAL( el->getDataProp<int>("myData"), 3 );
|
||||||
|
BOOST_CHECK_EQUAL( node->getIntValue("data-my-data"), 3 );
|
||||||
|
}
|
||||||
@@ -22,8 +22,6 @@
|
|||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/structure/SGWeakReferenced.hxx>
|
#include <simgear/structure/SGWeakReferenced.hxx>
|
||||||
|
|
||||||
#include <boost/call_traits.hpp>
|
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -59,14 +57,14 @@ namespace simgear
|
|||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void set( const std::string& name,
|
void set( const std::string& name,
|
||||||
typename boost::call_traits<T>::param_type val )
|
const T& val )
|
||||||
{
|
{
|
||||||
setValue(_node->getNode(name, true), val);
|
setValue(_node->getNode(name, true), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
T get( const std::string& name,
|
T get( const std::string& name,
|
||||||
typename boost::call_traits<T>::param_type def = T() )
|
const T& def = T() )
|
||||||
{
|
{
|
||||||
SGPropertyNode const* child = _node->getNode(name);
|
SGPropertyNode const* child = _node->getNode(name);
|
||||||
if( !child )
|
if( !child )
|
||||||
|
|||||||
Reference in New Issue
Block a user