diff --git a/nui/include/nui/frontend/attributes/impl/attribute.hpp b/nui/include/nui/frontend/attributes/impl/attribute.hpp index 62ab30da..5721736f 100644 --- a/nui/include/nui/frontend/attributes/impl/attribute.hpp +++ b/nui/include/nui/frontend/attributes/impl/attribute.hpp @@ -66,10 +66,24 @@ namespace Nui bool isRegular() const; bool isStringData() const; + bool defer() const; + void defer(bool doDefer) &; + Attribute&& defer(bool doDefer) && + { + defer(doDefer); + return std::move(*this); + } private: std::variant attributeImpl_{}; std::function&& element)> createEvent_{}; std::function clearEvent_{}; + bool defer_{false}; }; + + inline Attribute&& operator!(Attribute&& attribute) + { + attribute.defer(!attribute.defer()); + return std::move(attribute); + } } diff --git a/nui/include/nui/frontend/dom/element.hpp b/nui/include/nui/frontend/dom/element.hpp index 2bf8b754..932c6f3f 100644 --- a/nui/include/nui/frontend/dom/element.hpp +++ b/nui/include/nui/frontend/dom/element.hpp @@ -50,12 +50,14 @@ namespace Nui::Dom : ChildlessElement{elem} , children_{} , unsetup_{} + , deferredSetup_{} {} explicit Element(Nui::val val) : ChildlessElement{std::move(val)} , children_{} , unsetup_{} + , deferredSetup_{} {} Element(Element const&) = delete; @@ -69,7 +71,6 @@ namespace Nui::Dom destroy_(element_); } - template static std::shared_ptr makeElement(HtmlElement const& element) { auto elem = std::make_shared(element); @@ -102,6 +103,8 @@ namespace Nui::Dom { auto elem = makeElement(element); element_.call("appendChild", elem->element_); + if (elem->deferredSetup_) + elem->deferredSetup_(element); return children_.emplace_back(std::move(elem)); } auto slotFor(value_type const& value) @@ -152,6 +155,8 @@ namespace Nui::Dom return appendElement(element); auto elem = makeElement(element); element_.call("insertBefore", elem->element_, (*where)->element_); + if (elem->deferredSetup_) + elem->deferredSetup_(element); return *children_.insert(where, std::move(elem)); } @@ -162,8 +167,17 @@ namespace Nui::Dom { std::vector> eventClearers; eventClearers.reserve(element.attributes().size()); - for (auto const& attribute : element.attributes()) + std::vector deferredIndices; + + for (std::size_t i = 0; i != element.attributes().size(); ++i) { + auto const& attribute = element.attributes()[i]; + + if (attribute.defer()) + { + deferredIndices.push_back(i); + continue; + } if (attribute.isRegular()) attribute.setOn(*this); @@ -188,6 +202,40 @@ namespace Nui::Dom { unsetup_ = []() {}; } + + if (!deferredIndices.empty()) + { + deferredSetup_ = [this, deferredIndices = std::move(deferredIndices)](HtmlElement const& element) { + std::vector> eventClearers; + eventClearers.reserve(deferredIndices.size()); + + for (auto index : deferredIndices) + { + auto const& attribute = element.attributes()[index]; + + if (attribute.isRegular()) + attribute.setOn(*this); + + auto clear = attribute.getEventClear(); + if (clear) + { + eventClearers.push_back( + [clear = std::move(clear), id = attribute.createEvent(weak_from_base())]() { + clear(id); + }); + } + } + if (!eventClearers.empty()) + { + eventClearers.shrink_to_fit(); + unsetup_ = [unsetup1 = std::move(unsetup_), eventClearers = std::move(eventClearers)]() { + unsetup1(); + for (auto const& clear : eventClearers) + clear(); + }; + } + }; + } } auto insert(std::size_t where, HtmlElement const& element) @@ -239,6 +287,8 @@ namespace Nui::Dom element_.call("replaceWith", replacement); element_ = std::move(replacement); setup(element); + if (deferredSetup_) + deferredSetup_(element); } private: @@ -246,6 +296,7 @@ namespace Nui::Dom destroy_fn destroy_ = Detail::destroyByRemove; collection_type children_; std::function unsetup_; + std::function deferredSetup_; }; } diff --git a/nui/src/nui/frontend/attributes/impl/attribute.cpp b/nui/src/nui/frontend/attributes/impl/attribute.cpp index de934d13..99a9d1c2 100644 --- a/nui/src/nui/frontend/attributes/impl/attribute.cpp +++ b/nui/src/nui/frontend/attributes/impl/attribute.cpp @@ -37,5 +37,15 @@ namespace Nui { return std::holds_alternative(attributeImpl_); } + //--------------------------------------------------------------------------------------------------------------------- + bool Attribute::defer() const + { + return defer_; + } + //--------------------------------------------------------------------------------------------------------------------- + void Attribute::defer(bool doDefer) & + { + defer_ = doDefer; + } // ##################################################################################################################### } \ No newline at end of file