Skip to content

Commit 2327272

Browse files
committed
New more generic collection mechanism
Allows collecting of elements from components other than styles.
1 parent 4871bd3 commit 2327272

File tree

1 file changed

+118
-36
lines changed

1 file changed

+118
-36
lines changed

include/webxx.h

Lines changed: 118 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,15 @@ namespace Webxx { namespace internal {
290290
SCRIPT = 2,
291291
PLACEHOLDER = 3,
292292
VARIABLE = 4,
293+
HEAD = 5,
293294
};
294295

295296
struct HtmlNodeOptions {
296297
TagName tagName;
297298
Prefix prefix;
298299
SelfClosing selfClosing;
299-
CollectionTarget collectionTarget;
300+
CollectionTarget collects;
301+
CollectionTarget collection;
300302
};
301303

302304
typedef std::vector<HtmlAttribute> HtmlAttributes;
@@ -307,7 +309,7 @@ namespace Webxx { namespace internal {
307309
typedef std::function<HtmlNode()> ContentProducer;
308310

309311
struct HtmlNode {
310-
const HtmlNodeOptions options{none, none, false, NONE};
312+
const HtmlNodeOptions options{none, none, false, NONE, NONE};
311313
const HtmlAttributes attributes;
312314
mutable HtmlNodes children;
313315
const std::string contentOwned;
@@ -319,7 +321,7 @@ namespace Webxx { namespace internal {
319321
HtmlNode ()
320322
{}
321323
HtmlNode (const Placeholder &&tPlaceholder) :
322-
options{none, none, false, PLACEHOLDER},
324+
options{none, none, false, PLACEHOLDER, NONE},
323325
contentOwned{std::move(tPlaceholder)}
324326
{}
325327
HtmlNode (const ContentProducer &&tContentProducer) :
@@ -352,30 +354,45 @@ namespace Webxx { namespace internal {
352354
TagName TAG = none,
353355
Prefix PREFIX = none,
354356
SelfClosing SELF_CLOSING = false,
355-
CollectionTarget COLLECTS = NONE
357+
CollectionTarget COLLECTS = NONE,
358+
CollectionTarget COLLECTION = NONE
356359
>
357360
struct HtmlNodeDefined : public HtmlNode {
358361
HtmlNodeDefined () :
359-
HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS}, {}, {}, {}, 0} {}
362+
HtmlNode{{TAG, PREFIX, SELF_CLOSING, COLLECTS, COLLECTION}, {}, {}, {}, 0} {}
360363
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} {}
362365
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} {}
364367
template<typename ...T>
365368
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} {}
367370
};
368371

369372
struct HtmlStyleNode : HtmlNode {
370373
HtmlStyleNode () :
371-
HtmlNode{{styleTag, none, false, NONE}, {}, {}, {}, 0} {}
374+
HtmlNode{{styleTag, none, false, NONE, NONE}, {}, {}, {}, 0} {}
372375
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} {}
374377
template<typename ...T>
375378
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} {}
377380
};
378381

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+
379396
namespace exports {
380397
// HTML extensibility:
381398
template<TagName TAG>
@@ -394,7 +411,10 @@ namespace Webxx { namespace internal {
394411
using fragment = HtmlNodeDefined<>;
395412
using lazy = ContentProducer;
396413
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;
398418
}
399419
}}
400420

@@ -407,12 +427,21 @@ namespace Webxx { namespace internal {
407427
namespace Webxx { namespace internal {
408428

409429
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+
) :
411436
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+
},
413444
{},
414-
{tRootNode},
415-
std::move(tCss),
416445
tType
417446
)
418447
{}
@@ -423,12 +452,20 @@ namespace Webxx { namespace internal {
423452
Component (HtmlNode&& tRootNode) : ComponentBase(
424453
typeid(T).hash_code(),
425454
{},
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+
{}
427463
) {}
428-
Component (CssRules &&tCss, HtmlNode&& tRootNode) : ComponentBase(
464+
Component (HtmlStyleCollectionNode &&tCss, HtmlNode&& tRootNode, HtmlHeadCollectionNode&& tHeadNode) : ComponentBase(
429465
typeid(T).hash_code(),
430466
std::move(tCss),
431-
std::move(tRootNode)
467+
std::move(tRootNode),
468+
std::move(tHeadNode)
432469
) {}
433470
};
434471

@@ -448,13 +485,22 @@ namespace Webxx { namespace internal {
448485
constexpr char componentScopePrefix[] = "data-c";
449486

450487
struct CollectedCss {
451-
const ComponentType &componentType;
488+
const ComponentType componentType;
452489
const CssRules &css;
453490

454491
bool operator == (const CollectedCss &other) const noexcept {
455492
return (other.componentType == componentType);
456493
}
457494
};
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+
};
458504
}}
459505

460506
template<>
@@ -464,10 +510,16 @@ struct std::hash<Webxx::internal::CollectedCss> {
464510
}
465511
};
466512

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+
467520

468521
namespace Webxx { namespace internal {
469522
typedef std::function<void(const std::string_view, std::string &)> RenderReceiverFn;
470-
typedef std::unordered_set<CollectedCss> CollectedCsses;
471523
constexpr std::size_t renderBufferDefaultSize{16 * 1024};
472524

473525
inline void renderToInternalBuffer (const std::string_view data, std::string &buffer) {
@@ -497,30 +549,45 @@ namespace Webxx { namespace internal {
497549
{}
498550
};
499551

552+
typedef std::unordered_set<CollectedCss> CollectedCsses;
553+
typedef std::unordered_set<CollectedHtml> CollectedHtmls;
554+
500555
struct Collector {
501556
CollectedCsses csses;
557+
CollectedHtmls heads;
502558
RenderOptions options;
503559

504560
Collector(const RenderOptions &tOptions) :
505-
csses{}, options{tOptions} {};
561+
csses{}, heads{}, options{tOptions} {};
506562

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;
510567
}
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+
511577
if (node->contentLazy) {
512578
node->children.push_back(node->contentLazy());
513579
}
514-
this->collect(&node->children);
580+
581+
this->collect(&(node->children), nextComponent);
515582
}
516583

517-
void collect (const HtmlNodes* tNodes) {
584+
void collect (const HtmlNodes* tNodes, const ComponentType currentComponent) {
518585
for (auto &node : *tNodes) {
519-
this->collect(&node);
586+
this->collect(&node, currentComponent);
520587
}
521588
}
522589

523-
void collect (const void*) {}
590+
void collect (const void*, const ComponentType) {}
524591
};
525592

526593
struct Renderer {
@@ -587,6 +654,11 @@ namespace Webxx { namespace internal {
587654
nextComponent = node.componentType;
588655
}
589656

657+
if (node.options.collection != NONE) {
658+
// Nodes belonging to a collection will be rendered where they are collected:
659+
return;
660+
}
661+
590662
if (strlen(node.options.prefix)) {
591663
sendToRender(node.options.prefix);
592664
}
@@ -608,7 +680,7 @@ namespace Webxx { namespace internal {
608680
sendToRender(">");
609681
}
610682

611-
if (node.options.collectionTarget == PLACEHOLDER) {
683+
if (node.options.collects == PLACEHOLDER) {
612684
sendToRender(options.placeholderPopulator(node.contentOwned, node.options.tagName));
613685
} else {
614686
sendToRender(node.contentOwned);
@@ -619,14 +691,18 @@ namespace Webxx { namespace internal {
619691
render(node.children, nextComponent);
620692
}
621693

622-
if ((!node.componentType) && (!node.css.empty())) {
694+
if (!node.css.empty()) {
623695
render(node.css, 0);
624696
}
625697

626-
if (node.options.collectionTarget == CSS) {
698+
if (node.options.collects == CSS) {
627699
render(collector.csses, nextComponent);
628700
}
629701

702+
if (node.options.collects == HEAD) {
703+
render(collector.heads, nextComponent);
704+
}
705+
630706
if ((!node.options.selfClosing) && strlen(node.options.tagName)) {
631707
sendToRender("</");
632708
sendToRender(node.options.tagName);
@@ -704,9 +780,15 @@ namespace Webxx { namespace internal {
704780
}
705781
}
706782

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);
710792
}
711793
}
712794
};
@@ -715,7 +797,7 @@ namespace Webxx { namespace internal {
715797
template<typename V>
716798
Collector collect (V&& tNode, const RenderOptions &options) {
717799
Collector collector(options);
718-
collector.collect(&tNode);
800+
collector.collect(&tNode, 0);
719801
return collector;
720802
}
721803

0 commit comments

Comments
 (0)