Nui
Loading...
Searching...
No Matches
attribute_factory.hpp
Go to the documentation of this file.
1#pragma once
2
10
11#include <nui/frontend/val.hpp>
12
14{
15 namespace Detail
16 {
17 template <typename ElementT, typename T>
19 std::weak_ptr<ElementT> element,
20 T const& obs,
21 std::function<bool(std::shared_ptr<ElementT> const&)> onLock)
22 {
23 const auto eventId = globalEventContext.registerEvent(Event{
24 [element, obs, onLock = std::move(onLock)](auto eventId) {
25 if (auto shared = element.lock(); shared)
26 {
27 return onLock(shared);
28 }
29 obs.detachEvent(eventId);
30 return false;
31 },
32 [element]() {
33 return !element.expired();
34 }});
35 obs.attachEvent(eventId);
36 return eventId;
37 }
38
39 template <typename ElementT, typename T>
40 EventContext::EventIdType defaultAttributeEvent(std::weak_ptr<ElementT> element, T const& obs, char const* name)
41 {
42 return changeEventHandler(
43 element,
44 obs,
45 std::function<bool(std::shared_ptr<ElementT> const&)>{
46 [name, obs](std::shared_ptr<ElementT> const& shared) {
47 shared->setAttribute(name, obs.value());
48 return true;
49 }});
50 }
51
52 template <typename ElementT, typename T>
53 EventContext::EventIdType defaultPropertyEvent(std::weak_ptr<ElementT> element, T const& obs, char const* name)
54 {
55 return changeEventHandler(
56 element,
57 obs,
58 std::function<bool(std::shared_ptr<ElementT> const&)>{
59 [name, obs](std::shared_ptr<ElementT> const& shared) {
60 shared->setProperty(name, obs.value());
61 return true;
62 }});
63 }
64 }
65
67 {
68 public:
69 explicit constexpr PropertyFactory(char const* name)
70 : name_{name}
71 {}
72
73 constexpr PropertyFactory(PropertyFactory const& other) = default;
74 constexpr PropertyFactory(PropertyFactory&& other) noexcept = default;
77 ~PropertyFactory() = default;
78
79 constexpr char const* name() const
80 {
81 return name_;
82 };
83
84 template <typename U>
85 requires(
86 !IsObservedLike<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U> &&
88 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
89 Attribute operator=(U val) const
90 {
91 return Attribute{
92 [name = name(), val = std::move(val)](Dom::ChildlessElement& element) {
93 element.setProperty(name, val);
94 },
95 };
96 }
97
98 template <typename U>
100 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
101 Attribute operator=(U const& shared) const
102 {
103 return Attribute{
104 [name = name(), weak = std::weak_ptr{shared}](Dom::ChildlessElement& element) {
105 if (auto shared = weak.lock(); shared)
106 element.setProperty(name, shared->value());
107 },
108 [name = name(), weak = std::weak_ptr{shared}](std::weak_ptr<Dom::ChildlessElement> const& element) {
109 auto shared = weak.lock();
110 if (!shared)
112
113 const auto eventId = globalEventContext.registerEvent(Event{
114 [name, element, obsWeak = std::weak_ptr{shared}](auto eventId) {
115 auto obsShared = obsWeak.lock();
116 if (!obsShared)
117 {
118 return false;
119 }
120 if (auto shared = element.lock(); shared)
121 {
122 shared->setProperty(name, obsShared->value());
123 return true;
124 }
125 obsShared->detachEvent(eventId);
126 return false;
127 },
128 [element, obsWeak = std::weak_ptr{shared}]() {
129 return !element.expired() && !obsWeak.expired();
130 },
131 });
132 shared->attachEvent(eventId);
133 return eventId;
134 },
135 [weak = std::weak_ptr{shared}](EventContext::EventIdType id) {
136 if (auto shared = weak.lock(); shared)
137 shared->detachEvent(id);
138 },
139 };
140 }
141
142 template <typename U>
144 // NOLINTNEXTLINE
145 Attribute operator=(U&& val) const
146 {
147 auto shared = val.lock();
148 if (!shared)
149 return Attribute{};
150
151 return operator=(shared);
152 }
153
154 template <typename U>
156 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
157 Attribute operator=(U& val) const
158 {
159 return Attribute{
160 [name = name(), &val](Dom::ChildlessElement& element) {
161 element.setProperty(name, val.value());
162 },
163 [name = name(), &val](std::weak_ptr<Dom::ChildlessElement>&& element) {
165 std::move(element), Nui::Detail::CopyableObservedWrap{val}, name);
166 },
168 val.detachEvent(id);
169 },
170 };
171 }
172
173 template <typename RendererType, typename... ObservedValues>
174 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
177 {
178 return Attribute{
179 [name = name(), combinator](Dom::ChildlessElement& element) {
180 element.setProperty(name, combinator.value());
181 },
182 [name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
183 return Detail::defaultPropertyEvent(std::move(element), combinator, name);
184 },
185 [combinator](EventContext::EventIdType id) {
186 combinator.detachEvent(id);
187 },
188 };
189 }
190
191 template <typename RendererType, typename... ObservedValues>
192 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
195 {
196 return Attribute{
197 [name = name(), combinator](Dom::ChildlessElement& element) {
198 element.setProperty(name, combinator.value());
199 },
200 [name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
201 return Detail::defaultPropertyEvent(std::move(element), combinator, name);
202 },
203 [combinator](EventContext::EventIdType id) {
204 combinator.detachEvent(id);
205 },
206 };
207 }
208
209 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
210 Attribute operator=(std::function<void(Nui::val)> func) const
211 {
212 return Attribute{
213 [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
214 element.setProperty(name, [func](Nui::val val) {
215 func(std::move(val));
217 });
218 },
219 };
220 }
221
222 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
223 Attribute operator=(std::function<void()> func) const
224 {
225 return Attribute{
226 [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
227 element.setProperty(name, [func](Nui::val const&) {
228 func();
230 });
231 },
232 };
233 }
234
235 private:
236 char const* name_;
237 };
238
240 {
241 public:
242 explicit constexpr AttributeFactory(char const* name)
243 : name_{name}
244 {}
245
246 constexpr AttributeFactory(AttributeFactory const& other) = default;
247 constexpr AttributeFactory(AttributeFactory&& other) = default;
250 ~AttributeFactory() = default;
251
252 constexpr char const* name() const
253 {
254 return name_;
255 };
256
257 template <typename U>
258 requires(
259 !IsObservedLike<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U> &&
261 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
262 Attribute operator=(U val) const
263 {
264 return Attribute{
265 [name = name(), val = std::move(val)](Dom::ChildlessElement& element) {
266 element.setAttribute(name, val);
267 },
268 };
269 }
270
271 template <typename U>
273 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
274 Attribute operator=(U const& shared) const
275 {
276 return Attribute{
277 [name = name(), weak = std::weak_ptr{shared}](Dom::ChildlessElement& element) {
278 if (auto shared = weak.lock(); shared)
279 element.setAttribute(name, shared->value());
280 },
281 [name = name(), weak = std::weak_ptr{shared}](std::weak_ptr<Dom::ChildlessElement> const& element) {
282 auto shared = weak.lock();
283 if (!shared)
285
286 const auto eventId = globalEventContext.registerEvent(Event{
287 [name, element, obsWeak = std::weak_ptr{shared}](auto eventId) {
288 auto obsShared = obsWeak.lock();
289 if (!obsShared)
290 {
291 return false;
292 }
293 if (auto shared = element.lock(); shared)
294 {
295 shared->setAttribute(name, obsShared->value());
296 return true;
297 }
298 obsShared->detachEvent(eventId);
299 return false;
300 },
301 [element, obsWeak = std::weak_ptr{shared}]() {
302 return !element.expired() && !obsWeak.expired();
303 },
304 });
305 shared->attachEvent(eventId);
306 return eventId;
307 },
308 [weak = std::weak_ptr{shared}](EventContext::EventIdType id) {
309 if (auto shared = weak.lock(); shared)
310 shared->detachEvent(id);
311 },
312 };
313 }
314
315 template <typename U>
317 // NOLINTNEXTLINE
318 Attribute operator=(U&& val) const
319 {
320 auto shared = val.lock();
321 if (!shared)
322 return Attribute{};
323
324 return operator=(shared);
325 }
326
327 template <typename U>
329 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
330 Attribute operator=(U& val) const
331 {
332 return Attribute{
333 [name = name(), &val](Dom::ChildlessElement& element) {
334 element.setAttribute(name, val.value());
335 },
336 [name = name(), &val](std::weak_ptr<Dom::ChildlessElement>&& element) {
338 std::move(element), Nui::Detail::CopyableObservedWrap{val}, name);
339 },
341 val.detachEvent(id);
342 },
343 };
344 }
345
346 template <typename U>
348 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
349 Attribute operator=(Nui::Detail::Property<U> const& prop) const
350 {
351 return Attribute{
352 [name = name(), p = prop.prop](Dom::ChildlessElement& element) {
353 element.setProperty(name, p->value());
354 },
355 [name = name(), p = prop.prop](std::weak_ptr<Dom::ChildlessElement>&& element) {
357 std::move(element), Nui::Detail::CopyableObservedWrap{*p}, name);
358 },
359 [p = prop.prop](EventContext::EventIdType id) {
360 p->detachEvent(id);
361 },
362 };
363 }
364
365 template <typename U>
367 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
368 Attribute operator=(Nui::Detail::Property<U> const& prop) const
369 {
370 auto shared = prop.prop.lock();
371 if (!shared)
372 return Attribute{};
373
374 return Attribute{
375 [name = name(), weak = std::weak_ptr{shared}](Dom::ChildlessElement& element) {
376 if (auto shared = weak.lock(); shared)
377 element.setProperty(name, shared->value());
378 },
379 [name = name(), weak = std::weak_ptr{shared}](std::weak_ptr<Dom::ChildlessElement> const& element) {
380 auto shared = weak.lock();
381 if (!shared)
383
384 const auto eventId = globalEventContext.registerEvent(Event{
385 [name, element, obsWeak = std::weak_ptr{shared}](auto eventId) {
386 auto obsShared = obsWeak.lock();
387 if (!obsShared)
388 {
389 return false;
390 }
391 if (auto shared = element.lock(); shared)
392 {
393 shared->setProperty(name, obsShared->value());
394 return true;
395 }
396 obsShared->detachEvent(eventId);
397 return false;
398 },
399 [element, obsWeak = std::weak_ptr{shared}]() {
400 return !element.expired() && !obsWeak.expired();
401 },
402 });
403 shared->attachEvent(eventId);
404 return eventId;
405 },
406 [weak = std::weak_ptr{shared}](EventContext::EventIdType id) {
407 if (auto shared = weak.lock(); shared)
408 shared->detachEvent(id);
409 },
410 };
411 }
412
413 template <typename U>
414 requires(!IsObservedLike<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U>)
415 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
416 Attribute operator=(Nui::Detail::Property<U> const& prop) const
417 {
418 return Attribute{[name = name(), p = std::move(prop.prop)](Dom::ChildlessElement& element) {
419 element.setProperty(name, p);
420 }};
421 }
422
423 template <typename RendererType, typename... ObservedValues>
424 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
427 {
428 return Attribute{
429 [name = name(), combinator](Dom::ChildlessElement& element) {
430 element.setProperty(name, combinator.value());
431 },
432 [name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
433 return Detail::defaultPropertyEvent(std::move(element), combinator, name);
434 },
435 [combinator](EventContext::EventIdType id) {
436 combinator.detachEvent(id);
437 },
438 };
439 }
440
441 template <typename RendererType, typename... ObservedValues>
442 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
445 {
446 return Attribute{
447 [name = name(), combinator](Dom::ChildlessElement& element) {
448 element.setAttribute(name, combinator.value());
449 },
450 [name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
451 return Detail::defaultAttributeEvent(std::move(element), combinator, name);
452 },
453 [combinator](EventContext::EventIdType id) {
454 combinator.detachEvent(id);
455 },
456 };
457 }
458
459 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
460 Attribute operator=(std::function<void(Nui::val)> func) const
461 {
462 return Attribute{
463 [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
464 element.setAttribute(name, [func](Nui::val val) {
465 func(std::move(val));
467 });
468 },
469 };
470 }
471
472 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
473 Attribute operator=(std::function<void()> func) const
474 {
475 return Attribute{
476 [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
477 element.setAttribute(name, [func](Nui::val const&) {
478 func();
480 });
481 },
482 };
483 }
484
485 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
486 Attribute operator=(Nui::Detail::Property<std::function<void(Nui::val)>> func) const
487 {
488 return Attribute{
489 [name = name(), func = std::move(func.prop)](Dom::ChildlessElement& element) {
490 element.setProperty(name, [func](Nui::val val) {
491 func(std::move(val));
493 });
494 },
495 };
496 }
497
498 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
499 Attribute operator=(Nui::Detail::Property<std::function<void()>> func) const
500 {
501 return Attribute{
502 [name = name(), func = std::move(func.prop)](Dom::ChildlessElement& element) {
503 element.setProperty(name, [func](Nui::val const&) {
504 func();
506 });
507 },
508 };
509 }
510
511 private:
512 char const* name_;
513 };
514
516 {
517 public:
518 explicit constexpr EventFactory(char const* name)
519 : name_{name}
520 {}
521
522 constexpr EventFactory(EventFactory const& other) = default;
523 constexpr EventFactory(EventFactory&& other) = default;
526 ~EventFactory() = default;
527
528 constexpr char const* name() const
529 {
530 return name_;
531 };
532
533 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
534 Attribute operator=(std::function<void()> func) const
535 {
536 return Attribute{
537 [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
538 element.addEventListener(name, [func](Nui::val const&) {
539 func();
541 });
542 },
543 };
544 }
545
546 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
547 Attribute operator=(std::function<void(Nui::val)> func) const
548 {
549 return Attribute{
550 [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
551 element.addEventListener(name, [func](Nui::val val) {
552 func(std::move(val));
554 });
555 },
556 };
557 }
558
559 private:
560 char const* name_;
561 };
562
563 inline namespace Literals
564 {
565 constexpr AttributeFactory operator""_attr(char const* name, std::size_t)
566 {
567 return AttributeFactory{name};
568 }
569 constexpr PropertyFactory operator""_prop(char const* name, std::size_t)
570 {
571 return PropertyFactory{name};
572 }
573 constexpr EventFactory operator""_event(char const* name, std::size_t)
574 {
575 return EventFactory{name};
576 }
577 }
578
579 namespace Detail
580 {
581 template <typename T>
582 struct DeferWrap
583 {
584 T factory;
585
586 template <typename... Args>
587 // NOLINTNEXTLINE(misc-unconventional-assign-operator, cppcoreguidelines-c-copy-assignment-signature)
588 Attribute operator=(Args&&... args) const
589 {
590 auto attr = factory.operator=(std::forward<Args>(args)...);
591 attr.defer(true);
592 return attr;
593 };
594 };
595 }
596
597 template <typename T>
598 requires(
599 std::is_same_v<T, AttributeFactory> || std::is_same_v<T, PropertyFactory> || std::is_same_v<T, EventFactory>)
600 Detail::DeferWrap<T> operator!(T const& factory)
601 {
602 return Detail::DeferWrap<T>{.factory = T{std::move(factory)}};
603 }
604}
605
606// NOLINTBEGIN
607#define MAKE_HTML_VALUE_ATTRIBUTE_RENAME(NAME, HTML_NAME) \
608 namespace Nui::Attributes \
609 { \
610 static constexpr auto NAME = AttributeFactory{HTML_NAME}; \
611 }
612
613#define MAKE_HTML_VALUE_ATTRIBUTE(NAME) MAKE_HTML_VALUE_ATTRIBUTE_RENAME(NAME, #NAME)
614
615#define MAKE_HTML_EVENT_ATTRIBUTE_RENAME(NAME, HTML_ACTUAL) \
616 namespace Nui::Attributes \
617 { \
618 namespace Names \
619 { \
620 static constexpr auto Attr##NAME = fixToLower(HTML_ACTUAL); \
621 } \
622 static constexpr auto NAME = AttributeFactory{Names::Attr##NAME}; \
623 }
624// NOLINTEND
625
626#define MAKE_HTML_EVENT_ATTRIBUTE(NAME) MAKE_HTML_EVENT_ATTRIBUTE_RENAME(NAME, #NAME)
Definition attribute.hpp:15
bool defer() const
Definition attribute.cpp:41
Definition attribute_factory.hpp:240
AttributeFactory & operator=(AttributeFactory &&)=delete
constexpr AttributeFactory(AttributeFactory &&other)=default
constexpr AttributeFactory(char const *name)
Definition attribute_factory.hpp:242
Attribute operator=(ObservedValueCombinatorWithPropertyGenerator< RendererType, ObservedValues... > const &combinator) const
Definition attribute_factory.hpp:426
AttributeFactory & operator=(AttributeFactory const &)=delete
Attribute operator=(std::function< void()> func) const
Definition attribute_factory.hpp:473
Attribute operator=(std::function< void(Nui::val)> func) const
Definition attribute_factory.hpp:460
Attribute operator=(ObservedValueCombinatorWithGenerator< RendererType, ObservedValues... > const &combinator) const
Definition attribute_factory.hpp:444
Attribute operator=(Nui::Detail::Property< std::function< void(Nui::val)> > func) const
Definition attribute_factory.hpp:486
constexpr AttributeFactory(AttributeFactory const &other)=default
constexpr char const * name() const
Definition attribute_factory.hpp:252
Attribute operator=(Nui::Detail::Property< std::function< void()> > func) const
Definition attribute_factory.hpp:499
Definition attribute_factory.hpp:516
constexpr EventFactory(EventFactory const &other)=default
EventFactory & operator=(EventFactory &&)=delete
Attribute operator=(std::function< void(Nui::val)> func) const
Definition attribute_factory.hpp:547
constexpr EventFactory(EventFactory &&other)=default
Attribute operator=(std::function< void()> func) const
Definition attribute_factory.hpp:534
constexpr char const * name() const
Definition attribute_factory.hpp:528
constexpr EventFactory(char const *name)
Definition attribute_factory.hpp:518
EventFactory & operator=(EventFactory const &)=delete
Definition attribute_factory.hpp:67
constexpr PropertyFactory(char const *name)
Definition attribute_factory.hpp:69
Attribute operator=(ObservedValueCombinatorWithGenerator< RendererType, ObservedValues... > const &combinator) const
Definition attribute_factory.hpp:194
PropertyFactory & operator=(PropertyFactory &&)=delete
Attribute operator=(std::function< void()> func) const
Definition attribute_factory.hpp:223
Attribute operator=(std::function< void(Nui::val)> func) const
Definition attribute_factory.hpp:210
PropertyFactory & operator=(PropertyFactory const &)=delete
Attribute operator=(ObservedValueCombinatorWithPropertyGenerator< RendererType, ObservedValues... > const &combinator) const
Definition attribute_factory.hpp:176
constexpr PropertyFactory(PropertyFactory &&other) noexcept=default
constexpr char const * name() const
Definition attribute_factory.hpp:79
constexpr PropertyFactory(PropertyFactory const &other)=default
The basic element cannot have children and does not hold explicit ownership of them.
Definition childless_element.hpp:19
EventRegistry::EventIdType EventIdType
Definition event_context.hpp:40
static constexpr auto invalidEventId
Definition event_context.hpp:41
void executeActiveEventsImmediately()
Definition event_context.hpp:64
EventIdType registerEvent(Event event)
Definition event_context.hpp:52
Definition event.hpp:46
constexpr void detachEvent(auto eventId) const
Definition observed_value_combinator.hpp:56
Definition observed_value_combinator.hpp:108
constexpr auto value() const
Definition observed_value_combinator.hpp:122
Definition observed_value_combinator.hpp:143
Definition property.hpp:42
Definition observed_value.hpp:1540
Definition observed_value.hpp:1534
Definition observed_value.hpp:1536
Definition observed_value.hpp:1538
EventContext::EventIdType changeEventHandler(std::weak_ptr< ElementT > element, T const &obs, std::function< bool(std::shared_ptr< ElementT > const &)> onLock)
Definition attribute_factory.hpp:18
EventContext::EventIdType defaultPropertyEvent(std::weak_ptr< ElementT > element, T const &obs, char const *name)
Definition attribute_factory.hpp:53
EventContext::EventIdType defaultAttributeEvent(std::weak_ptr< ElementT > element, T const &obs, char const *name)
Definition attribute_factory.hpp:40
Definition attribute_factory.hpp:14
static constexpr auto extractJsonMember(nlohmann::json const &json) -> decltype(auto)
Definition rpc_hub.hpp:29
thread_local EventContext globalEventContext
Definition event_context.cpp:5
RendererType
Definition materialize.hpp:48
emscripten::val val
Definition val.hpp:5
Definition observed_value.hpp:1546
Definition property.hpp:13
T prop
Definition property.hpp:14