@@ -290,13 +290,15 @@ namespace Webxx { namespace internal {
290
290
SCRIPT = 2 ,
291
291
PLACEHOLDER = 3 ,
292
292
VARIABLE = 4 ,
293
+ HEAD = 5 ,
293
294
};
294
295
295
296
struct HtmlNodeOptions {
296
297
TagName tagName;
297
298
Prefix prefix;
298
299
SelfClosing selfClosing;
299
- CollectionTarget collectionTarget;
300
+ CollectionTarget collects;
301
+ CollectionTarget collection;
300
302
};
301
303
302
304
typedef std::vector<HtmlAttribute> HtmlAttributes;
@@ -307,7 +309,7 @@ namespace Webxx { namespace internal {
307
309
typedef std::function<HtmlNode()> ContentProducer;
308
310
309
311
struct HtmlNode {
310
- const HtmlNodeOptions options{none, none, false , NONE};
312
+ const HtmlNodeOptions options{none, none, false , NONE, NONE };
311
313
const HtmlAttributes attributes;
312
314
mutable HtmlNodes children;
313
315
const std::string contentOwned;
@@ -319,7 +321,7 @@ namespace Webxx { namespace internal {
319
321
HtmlNode ()
320
322
{}
321
323
HtmlNode (const Placeholder &&tPlaceholder) :
322
- options{none, none, false , PLACEHOLDER},
324
+ options{none, none, false , PLACEHOLDER, NONE },
323
325
contentOwned{std::move (tPlaceholder)}
324
326
{}
325
327
HtmlNode (const ContentProducer &&tContentProducer) :
@@ -352,30 +354,45 @@ namespace Webxx { namespace internal {
352
354
TagName TAG = none,
353
355
Prefix PREFIX = none,
354
356
SelfClosing SELF_CLOSING = false ,
355
- CollectionTarget COLLECTS = NONE
357
+ CollectionTarget COLLECTS = NONE,
358
+ CollectionTarget COLLECTION = NONE
356
359
>
357
360
struct HtmlNodeDefined : public HtmlNode {
358
361
HtmlNodeDefined () :
359
- HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS}, {}, {}, {}, 0 } {}
362
+ HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS, COLLECTION }, {}, {}, {}, 0 } {}
360
363
HtmlNodeDefined (std::initializer_list<HtmlNode> &&tChildren) :
361
- HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS}, {}, std::move (tChildren), {}, 0 } {}
364
+ HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS, COLLECTION }, {}, std::move (tChildren), {}, 0 } {}
362
365
HtmlNodeDefined (HtmlNodes &&tChildren) :
363
- HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS}, {}, std::move (tChildren), {}, 0 } {}
366
+ HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS, COLLECTION }, {}, std::move (tChildren), {}, 0 } {}
364
367
template <typename ...T>
365
368
HtmlNodeDefined (HtmlAttributes &&tAttributes, T&& ...tChildren) :
366
- HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS}, std::move (tAttributes), {std::forward<T>(tChildren)...}, {}, 0 } {}
369
+ HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS, COLLECTION }, std::move (tAttributes), {std::forward<T>(tChildren)...}, {}, 0 } {}
367
370
};
368
371
369
372
struct HtmlStyleNode : HtmlNode {
370
373
HtmlStyleNode () :
371
- HtmlNode{{styleTag, none, false , NONE}, {}, {}, {}, 0 } {}
374
+ HtmlNode{{styleTag, none, false , NONE, NONE }, {}, {}, {}, 0 } {}
372
375
HtmlStyleNode (std::initializer_list<CssRule> &&tCss) :
373
- HtmlNode{{styleTag, none, false , NONE}, {}, {}, std::move (tCss), 0 } {}
376
+ HtmlNode{{styleTag, none, false , NONE, NONE }, {}, {}, std::move (tCss), 0 } {}
374
377
template <typename ...T>
375
378
HtmlStyleNode (HtmlAttributes &&tAttributes, T&& ...tCss) :
376
- HtmlNode{{styleTag, none, false , NONE}, std::move (tAttributes), {}, {std::forward<T>(tCss)...}, 0 } {}
379
+ HtmlNode{{styleTag, none, false , NONE, NONE, NONE }, std::move (tAttributes), {}, {std::forward<T>(tCss)...}, 0 } {}
377
380
};
378
381
382
+ struct HtmlStyleCollectionNode : HtmlNode {
383
+ HtmlStyleCollectionNode () :
384
+ HtmlNode{{none, none, false , NONE, CSS}, {}, {}, {}, 0 } {}
385
+ HtmlStyleCollectionNode (std::initializer_list<CssRule> &&tCss) :
386
+ HtmlNode{{none, none, false , NONE, CSS}, {}, {}, std::move (tCss), 0 } {}
387
+ HtmlStyleCollectionNode (CssRules &&tCss) :
388
+ HtmlNode{{none, none, false , NONE, CSS}, {}, {}, std::move (tCss), 0 } {}
389
+ template <typename ...T>
390
+ HtmlStyleCollectionNode (HtmlAttributes &&tAttributes, T&& ...tCss) :
391
+ HtmlNode{{none, none, false , NONE, CSS}, std::move (tAttributes), {}, {std::forward<T>(tCss)...}, 0 } {}
392
+ };
393
+
394
+ typedef HtmlNodeDefined<none, none, false , NONE, HEAD> HtmlHeadCollectionNode;
395
+
379
396
namespace exports {
380
397
// HTML extensibility:
381
398
template <TagName TAG>
@@ -394,7 +411,10 @@ namespace Webxx { namespace internal {
394
411
using fragment = HtmlNodeDefined<>;
395
412
using lazy = ContentProducer;
396
413
using style = HtmlStyleNode;
397
- using styleTarget = HtmlNodeDefined<styleTag, none, false , CSS>;
414
+ using styleTarget = HtmlNodeDefined<styleTag, none, false , CSS, NONE>;
415
+ using styleSrc = HtmlStyleCollectionNode;
416
+ using headTarget = HtmlNodeDefined<none, none, false , HEAD, NONE>;
417
+ using headSrc = HtmlHeadCollectionNode;
398
418
}
399
419
}}
400
420
@@ -407,12 +427,21 @@ namespace Webxx { namespace internal {
407
427
namespace Webxx { namespace internal {
408
428
409
429
struct ComponentBase : public HtmlNode {
410
- ComponentBase (const ComponentType tType, CssRules &&tCss, HtmlNode&& tRootNode) :
430
+ ComponentBase (
431
+ const ComponentType tType,
432
+ HtmlStyleCollectionNode &&tCss,
433
+ HtmlNode &&tRoot,
434
+ HtmlHeadCollectionNode &&tHead
435
+ ) :
411
436
HtmlNode (
412
- {none, none, false , NONE},
437
+ {none, none, false , NONE, NONE},
438
+ {},
439
+ {
440
+ std::move (tRoot),
441
+ std::move (tCss),
442
+ std::move (tHead),
443
+ },
413
444
{},
414
- {tRootNode},
415
- std::move (tCss),
416
445
tType
417
446
)
418
447
{}
@@ -423,12 +452,20 @@ namespace Webxx { namespace internal {
423
452
Component (HtmlNode&& tRootNode) : ComponentBase(
424
453
typeid (T).hash_code(),
425
454
{},
426
- std::move (tRootNode)
455
+ std::move (tRootNode),
456
+ {}
457
+ ) {}
458
+ Component (HtmlStyleCollectionNode &&tCss, HtmlNode&& tRootNode) : ComponentBase(
459
+ typeid (T).hash_code(),
460
+ std::move(tCss),
461
+ std::move(tRootNode),
462
+ {}
427
463
) {}
428
- Component (CssRules &&tCss, HtmlNode&& tRootNode) : ComponentBase(
464
+ Component (HtmlStyleCollectionNode &&tCss, HtmlNode&& tRootNode, HtmlHeadCollectionNode&& tHeadNode ) : ComponentBase(
429
465
typeid (T).hash_code(),
430
466
std::move(tCss),
431
- std::move(tRootNode)
467
+ std::move(tRootNode),
468
+ std::move(tHeadNode)
432
469
) {}
433
470
};
434
471
@@ -448,13 +485,22 @@ namespace Webxx { namespace internal {
448
485
constexpr char componentScopePrefix[] = " data-c" ;
449
486
450
487
struct CollectedCss {
451
- const ComponentType & componentType;
488
+ const ComponentType componentType;
452
489
const CssRules &css;
453
490
454
491
bool operator == (const CollectedCss &other) const noexcept {
455
492
return (other.componentType == componentType);
456
493
}
457
494
};
495
+
496
+ struct CollectedHtml {
497
+ const ComponentType componentType;
498
+ const HtmlNodes &nodes;
499
+
500
+ bool operator == (const CollectedHtml &other) const noexcept {
501
+ return (other.componentType == componentType);
502
+ }
503
+ };
458
504
}}
459
505
460
506
template <>
@@ -464,10 +510,16 @@ struct std::hash<Webxx::internal::CollectedCss> {
464
510
}
465
511
};
466
512
513
+ template <>
514
+ struct std ::hash<Webxx::internal::CollectedHtml> {
515
+ std::size_t operator () (const Webxx::internal::CollectedHtml &collectedHtml) const noexcept {
516
+ return std::hash<std::size_t >{}(collectedHtml.componentType );
517
+ }
518
+ };
519
+
467
520
468
521
namespace Webxx { namespace internal {
469
522
typedef std::function<void (const std::string_view, std::string &)> RenderReceiverFn;
470
- typedef std::unordered_set<CollectedCss> CollectedCsses;
471
523
constexpr std::size_t renderBufferDefaultSize{16 * 1024 };
472
524
473
525
inline void renderToInternalBuffer (const std::string_view data, std::string &buffer) {
@@ -497,30 +549,45 @@ namespace Webxx { namespace internal {
497
549
{}
498
550
};
499
551
552
+ typedef std::unordered_set<CollectedCss> CollectedCsses;
553
+ typedef std::unordered_set<CollectedHtml> CollectedHtmls;
554
+
500
555
struct Collector {
501
556
CollectedCsses csses;
557
+ CollectedHtmls heads;
502
558
RenderOptions options;
503
559
504
560
Collector (const RenderOptions &tOptions) :
505
- csses{}, options{tOptions} {};
561
+ csses{}, heads{}, options{tOptions} {};
506
562
507
- void collect (const HtmlNode* node) {
508
- if (node->componentType && !node->css .empty ()) {
509
- csses.insert ({node->componentType , node->css });
563
+ void collect (const HtmlNode* node, const ComponentType currentComponent) {
564
+ ComponentType nextComponent = currentComponent;
565
+ if (node->componentType ) {
566
+ nextComponent = node->componentType ;
510
567
}
568
+
569
+ if (node->options .collection == HEAD && !node->children .empty ()) {
570
+ heads.insert ({nextComponent, node->children });
571
+ }
572
+
573
+ if (node->options .collection == CSS && !node->css .empty ()) {
574
+ csses.insert ({nextComponent, node->css });
575
+ }
576
+
511
577
if (node->contentLazy ) {
512
578
node->children .push_back (node->contentLazy ());
513
579
}
514
- this ->collect (&node->children );
580
+
581
+ this ->collect (&(node->children ), nextComponent);
515
582
}
516
583
517
- void collect (const HtmlNodes* tNodes) {
584
+ void collect (const HtmlNodes* tNodes, const ComponentType currentComponent ) {
518
585
for (auto &node : *tNodes) {
519
- this ->collect (&node);
586
+ this ->collect (&node, currentComponent );
520
587
}
521
588
}
522
589
523
- void collect (const void *) {}
590
+ void collect (const void *, const ComponentType ) {}
524
591
};
525
592
526
593
struct Renderer {
@@ -587,6 +654,11 @@ namespace Webxx { namespace internal {
587
654
nextComponent = node.componentType ;
588
655
}
589
656
657
+ if (node.options .collection != NONE) {
658
+ // Nodes belonging to a collection will be rendered where they are collected:
659
+ return ;
660
+ }
661
+
590
662
if (strlen (node.options .prefix )) {
591
663
sendToRender (node.options .prefix );
592
664
}
@@ -608,7 +680,7 @@ namespace Webxx { namespace internal {
608
680
sendToRender (" >" );
609
681
}
610
682
611
- if (node.options .collectionTarget == PLACEHOLDER) {
683
+ if (node.options .collects == PLACEHOLDER) {
612
684
sendToRender (options.placeholderPopulator (node.contentOwned , node.options .tagName ));
613
685
} else {
614
686
sendToRender (node.contentOwned );
@@ -619,14 +691,18 @@ namespace Webxx { namespace internal {
619
691
render (node.children , nextComponent);
620
692
}
621
693
622
- if (( !node.componentType ) && (!node. css .empty () )) {
694
+ if (!node.css .empty ()) {
623
695
render (node.css , 0 );
624
696
}
625
697
626
- if (node.options .collectionTarget == CSS) {
698
+ if (node.options .collects == CSS) {
627
699
render (collector.csses , nextComponent);
628
700
}
629
701
702
+ if (node.options .collects == HEAD) {
703
+ render (collector.heads , nextComponent);
704
+ }
705
+
630
706
if ((!node.options .selfClosing ) && strlen (node.options .tagName )) {
631
707
sendToRender (" </" );
632
708
sendToRender (node.options .tagName );
@@ -704,9 +780,15 @@ namespace Webxx { namespace internal {
704
780
}
705
781
}
706
782
707
- void render (const CollectedCsses &csses, const ComponentType) {
708
- for (auto &css : csses) {
709
- render (css.css , css.componentType );
783
+ void render (const CollectedCsses &collectedCsses, const ComponentType) {
784
+ for (auto &collectedCss : collectedCsses) {
785
+ render (collectedCss.css , collectedCss.componentType );
786
+ }
787
+ }
788
+
789
+ void render (const CollectedHtmls &collectedHtmls, const ComponentType) {
790
+ for (auto &collectedHtml : collectedHtmls) {
791
+ render (collectedHtml.nodes , collectedHtml.componentType );
710
792
}
711
793
}
712
794
};
@@ -715,7 +797,7 @@ namespace Webxx { namespace internal {
715
797
template <typename V>
716
798
Collector collect (V&& tNode, const RenderOptions &options) {
717
799
Collector collector (options);
718
- collector.collect (&tNode);
800
+ collector.collect (&tNode, 0 );
719
801
return collector;
720
802
}
721
803
0 commit comments