@@ -389,7 +389,6 @@ impl<T: WriteHtml> WriteHtml for ManuallyDrop<T> {
389
389
///
390
390
/// The [`html!`] macro uses them for all tags that contain `-` making it
391
391
/// possible to use web-components.
392
- #[ must_use]
393
392
pub struct CustomElement < Html : WriteHtml , S : ElementState > {
394
393
html : ManuallyDrop < Html > ,
395
394
name : ManuallyDrop < Cow < ' static , str > > ,
@@ -444,64 +443,37 @@ impl<Html: WriteHtml> CustomElement<Html, Tag> {
444
443
/// [`AnyAttributeValue`], without checking for invalid characters.
445
444
///
446
445
/// Note: This function does contain the check for [invalid attribute names](https://www.w3.org/TR/2011/WD-html5-20110525/syntax.html#attributes-0) only in debug builds, failing to ensure valid keys can lead to broken HTML output.
447
- pub fn custom_attr_unchecked (
448
- & mut self ,
449
- key : impl Display ,
450
- value : impl ToAttribute < Any > ,
451
- ) {
446
+ pub fn custom_attr_unchecked ( & mut self , key : impl Display , value : impl ToAttribute < Any > ) {
452
447
debug_assert ! ( !key. to_string( ) . chars( ) . any( |c| c. is_whitespace( )
453
448
|| c. is_control( )
454
449
|| matches!( c, '\0' | '"' | '\'' | '>' | '/' | '=' ) ) , "invalid key `{key}`, https://www.w3.org/TR/2011/WD-html5-20110525/syntax.html#attributes-0" ) ;
455
450
write ! ( self . html, " {key}" ) ;
456
451
value. write ( & mut self . html ) ;
457
452
}
458
453
459
- pub fn custom_attr_composed ( self , key : impl Display ) -> CustomElement < Html , CustomAttr > {
460
- assert ! ( !key. to_string( ) . chars( ) . any( |c| c. is_whitespace( )
461
- || c. is_control( )
462
- || matches!( c, '\0' | '"' | '\'' | '>' | '/' | '=' ) ) , "invalid key `{key}`, https://www.w3.org/TR/2011/WD-html5-20110525/syntax.html#attributes-0" ) ;
463
- self . custom_attr_composed_unchecked ( key)
464
- }
465
-
466
- pub fn custom_attr_composed_unchecked (
467
- mut self ,
468
- key : impl Display ,
469
- ) -> CustomElement < Html , CustomAttr > {
470
- debug_assert ! ( !key. to_string( ) . chars( ) . any( |c| c. is_whitespace( )
471
- || c. is_control( )
472
- || matches!( c, '\0' | '"' | '\'' | '>' | '/' | '=' ) ) , "invalid key `{key}`, https://www.w3.org/TR/2011/WD-html5-20110525/syntax.html#attributes-0" ) ;
473
- write ! ( self . html, " {key}=\" " ) ;
474
- self . change_state ( )
475
- }
476
-
477
- pub fn body ( mut self ) -> CustomElement < Html , Body > {
454
+ // TODO, use closure like body
455
+ // pub fn custom_attr_composed(self, key: impl Display) -> CustomElement<Html,
456
+ // CustomAttr> { assert!(!key.to_string().chars().any(|c|
457
+ // c.is_whitespace() || c.is_control()
458
+ // || matches!(c, '\0' | '"' | '\'' | '>' | '/' | '=')), "invalid key `{key}`, https://www.w3.org/TR/2011/WD-html5-20110525/syntax.html#attributes-0");
459
+ // self.custom_attr_composed_unchecked(key)
460
+ // }
461
+
462
+ // pub fn custom_attr_composed_unchecked(
463
+ // mut self,
464
+ // key: impl Display,
465
+ // ) -> CustomElement<Html, CustomAttr> {
466
+ // debug_assert!(!key.to_string().chars().any(|c| c.is_whitespace()
467
+ // || c.is_control()
468
+ // || matches!(c, '\0' | '"' | '\'' | '>' | '/' | '=')), "invalid key `{key}`, https://www.w3.org/TR/2011/WD-html5-20110525/syntax.html#attributes-0");
469
+ // write!(self.html, " {key}=\"");
470
+ // self.change_state()
471
+ // }
472
+
473
+ pub fn body ( mut self , body : impl FnOnce ( & mut Html ) ) {
478
474
self . html . write_gt ( ) ;
479
- self . change_state ( )
480
- }
481
- }
482
-
483
- impl < Html : WriteHtml > WriteHtml for CustomElement < Html , Body > {
484
- fn write_str ( & mut self , s : & str ) {
485
- self . html . write_str ( s) ;
486
- }
487
-
488
- fn write_char ( & mut self , c : char ) {
489
- self . html . write_char ( c) ;
490
- }
491
-
492
- fn write_fmt ( & mut self , a : std:: fmt:: Arguments ) {
493
- self . html . write_fmt ( a) ;
494
- }
495
- }
496
-
497
- impl < Html : WriteHtml > CustomElement < Html , Body > {
498
- pub fn child_expr ( mut self , child : impl ToHtml ) -> Self {
499
- child. to_html ( & mut self ) ;
500
- self
501
- }
502
-
503
- pub fn child < C > ( self , child : impl FnOnce ( Self ) -> C ) -> C {
504
- child ( self )
475
+ body ( & mut self . html ) ;
476
+ self . change_state :: < Body > ( ) ;
505
477
}
506
478
}
507
479
@@ -516,14 +488,6 @@ impl<Html: WriteHtml, S: ElementState> CustomElement<Html, S> {
516
488
state : PhantomData ,
517
489
}
518
490
}
519
-
520
- pub fn close ( mut self ) -> Html {
521
- S :: close_tag ( & mut self . html ) ;
522
- self . html . write_close_tag_unchecked ( self . name . as_ref ( ) ) ;
523
- let html = unsafe { ManuallyDrop :: take ( & mut self . html ) } ;
524
- std:: mem:: forget ( self ) ;
525
- html
526
- }
527
491
}
528
492
529
493
impl < Html : WriteHtml , S : ElementState > Drop for CustomElement < Html , S > {
@@ -533,20 +497,6 @@ impl<Html: WriteHtml, S: ElementState> Drop for CustomElement<Html, S> {
533
497
}
534
498
}
535
499
536
- impl < Html : WriteHtml > CustomElement < Html , CustomAttr > {
537
- pub fn attr_value ( mut self , value : impl ToAttribute < Any > ) -> Self {
538
- if !value. is_unset ( ) {
539
- value. write_inner ( & mut self . html ) ;
540
- }
541
- self
542
- }
543
-
544
- pub fn close_attr ( mut self ) -> CustomElement < Html , Tag > {
545
- self . html . write_quote ( ) ;
546
- self . change_state ( )
547
- }
548
- }
549
-
550
500
/// Puts content directly into HTML bypassing HTML-escaping.
551
501
///
552
502
/// ```
@@ -567,6 +517,30 @@ impl<'a> RawHtml<'a> {
567
517
}
568
518
}
569
519
520
+ pub struct Fragment < F > ( pub F ) ;
521
+
522
+ // TODO reconsider elements implementing WriteHtml, maybe it would be better for them to implement a way to access the underlying `Html`
523
+ impl < F > Fragment < F > {
524
+ #[ allow( non_snake_case) ]
525
+ pub fn EMPTY ( self , html : impl WriteHtml ) { }
526
+ }
527
+
528
+ impl < F : FnOnce ( Html ) , Html : WriteHtml > IntoHtml < Html > for Fragment < F > {
529
+ fn into_html ( self , html : Html ) {
530
+ self . 0 ( html) ;
531
+ }
532
+ }
533
+
534
+ pub trait IntoHtml < Html > {
535
+ fn into_html ( self , html : Html ) ;
536
+ }
537
+
538
+ impl < T : ToHtml , Html : WriteHtml > IntoHtml < Html > for T {
539
+ fn into_html ( self , html : Html ) {
540
+ self . to_html ( html) ;
541
+ }
542
+ }
543
+
570
544
pub trait ToHtml {
571
545
fn to_html ( & self , html : impl WriteHtml ) ;
572
546
}
@@ -629,3 +603,49 @@ impl ElementState for Body {
629
603
pub trait ElementState {
630
604
fn close_tag ( html : impl WriteHtml ) ;
631
605
}
606
+
607
+ forr ! { $type : ty in [ & str , String , Cow <' _, str >] $*
608
+ impl ToHtml for $type {
609
+ fn to_html( & self , mut out: impl WriteHtml ) {
610
+ write!( out, "{}" , html_escape:: encode_text( & self ) ) ;
611
+ }
612
+ }
613
+
614
+ impl ToScript for $type {
615
+ fn to_script( & self , mut out: impl WriteHtml ) {
616
+ write!( out, "{}" , html_escape:: encode_script( & self ) ) ;
617
+ }
618
+ }
619
+
620
+ impl ToStyle for $type {
621
+ fn to_style( & self , mut out: impl WriteHtml ) {
622
+ write!( out, "{}" , html_escape:: encode_style( & self ) ) ;
623
+ }
624
+ }
625
+ }
626
+
627
+ impl ToHtml for char {
628
+ fn to_html ( & self , mut out : impl WriteHtml ) {
629
+ write ! ( out, "{}" , html_escape:: encode_text( & self . to_string( ) ) ) ;
630
+ }
631
+ }
632
+
633
+ pub trait ToScript {
634
+ fn to_script ( & self , out : impl WriteHtml ) ;
635
+ }
636
+
637
+ impl < T : ToScript > ToScript for & T {
638
+ fn to_script ( & self , out : impl WriteHtml ) {
639
+ T :: to_script ( self , out) ;
640
+ }
641
+ }
642
+
643
+ pub trait ToStyle {
644
+ fn to_style ( & self , out : impl WriteHtml ) ;
645
+ }
646
+
647
+ impl < T : ToStyle > ToStyle for & T {
648
+ fn to_style ( & self , out : impl WriteHtml ) {
649
+ T :: to_style ( self , out) ;
650
+ }
651
+ }
0 commit comments