From d77ba7d2dba2bed9beb5ea1beaeeebfe3e237a46 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Wed, 28 May 2014 18:09:34 +0200 Subject: [PATCH] canvas::Element: setter/getter for HTML5 style data-* properties. --- simgear/canvas/elements/CMakeLists.txt | 7 +- simgear/canvas/elements/CanvasElement.cxx | 71 ++++++++++++++++++- simgear/canvas/elements/CanvasElement.hxx | 31 +++++++- simgear/canvas/elements/CanvasGroup.cxx | 8 ++- .../canvas/elements/canvas_element_test.cpp | 54 ++++++++++++++ simgear/props/PropertyBasedElement.hxx | 6 +- 6 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 simgear/canvas/elements/canvas_element_test.cpp diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt index bd21c13d..2b537c0c 100644 --- a/simgear/canvas/elements/CMakeLists.txt +++ b/simgear/canvas/elements/CMakeLists.txt @@ -23,4 +23,9 @@ set(SOURCES ) simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}") -simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}") \ No newline at end of file +simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}") + +add_boost_test(canvas_element + SOURCES canvas_element_test.cpp + LIBRARIES ${TEST_LIBS} +) \ No newline at end of file diff --git a/simgear/canvas/elements/CanvasElement.cxx b/simgear/canvas/elements/CanvasElement.cxx index 9bb75b12..1c506fbc 100644 --- a/simgear/canvas/elements/CanvasElement.cxx +++ b/simgear/canvas/elements/CanvasElement.cxx @@ -437,7 +437,8 @@ namespace canvas else if( boost::starts_with(name, "blend-") ) return (void)(_attributes_dirty |= BLEND_FUNC); } - else if( parent->getParent() == _node + else if( parent + && parent->getParent() == _node && parent->getNameString() == NAME_TRANSFORM ) { _attributes_dirty |= TRANSFORM; @@ -634,6 +635,74 @@ namespace canvas 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; diff --git a/simgear/canvas/elements/CanvasElement.hxx b/simgear/canvas/elements/CanvasElement.hxx index f8b4bcf5..9a85a23c 100644 --- a/simgear/canvas/elements/CanvasElement.hxx +++ b/simgear/canvas/elements/CanvasElement.hxx @@ -104,6 +104,30 @@ namespace canvas bool addEventListener(const std::string& type, const EventListener& cb); virtual void clearEventListener(); + template + void setDataProp( const std::string& name, + const T& val ) + { + const std::string& attr = dataPropToAttrName(name); + if( !attr.empty() ) + set(attr, val); + else + SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name); + } + + template + T getDataProp( const std::string& name, + const T& def = T() ) + { + const std::string& attr = dataPropToAttrName(name); + if( !attr.empty() ) + return get(attr, def); + else + SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name); + + return def; + } + virtual bool accept(EventVisitor& visitor); virtual bool ascend(EventVisitor& visitor); virtual bool traverse(EventVisitor& visitor); @@ -195,12 +219,15 @@ namespace canvas ElementPtr >::type create( const CanvasWeakPtr& canvas, const SGPropertyNode_ptr& node, - const Style& style, - Element* parent ) + const Style& style = Style(), + Element* parent = NULL ) { 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: enum Attributes diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx index ce86320a..e2c88885 100644 --- a/simgear/canvas/elements/CanvasGroup.cxx +++ b/simgear/canvas/elements/CanvasGroup.cxx @@ -320,10 +320,12 @@ namespace canvas //---------------------------------------------------------------------------- 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" ) - return handleZIndexChanged( getChild(node->getParent()), - node->getIntValue() ); + return handleZIndexChanged(getChild(parent), node->getIntValue()); } //---------------------------------------------------------------------------- diff --git a/simgear/canvas/elements/canvas_element_test.cpp b/simgear/canvas/elements/canvas_element_test.cpp new file mode 100644 index 00000000..fe3c2ee7 --- /dev/null +++ b/simgear/canvas/elements/canvas_element_test.cpp @@ -0,0 +1,54 @@ +/// Unit tests for canvas::Element +#define BOOST_TEST_MODULE canvas +#include + +#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::CanvasWeakPtr(), node); + + el->setDataProp("myData", 3); + BOOST_CHECK_EQUAL( el->getDataProp("myData"), 3 ); + BOOST_CHECK_EQUAL( node->getIntValue("data-my-data"), 3 ); +} diff --git a/simgear/props/PropertyBasedElement.hxx b/simgear/props/PropertyBasedElement.hxx index a0682fd0..dcaceaf0 100644 --- a/simgear/props/PropertyBasedElement.hxx +++ b/simgear/props/PropertyBasedElement.hxx @@ -22,8 +22,6 @@ #include #include -#include - namespace simgear { @@ -59,14 +57,14 @@ namespace simgear template void set( const std::string& name, - typename boost::call_traits::param_type val ) + const T& val ) { setValue(_node->getNode(name, true), val); } template T get( const std::string& name, - typename boost::call_traits::param_type def = T() ) + const T& def = T() ) { SGPropertyNode const* child = _node->getNode(name); if( !child ) -- 2.39.5