@itrocks/template 0.0.39 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/cjs/template.js +31 -6
- package/esm/template.js +31 -6
- package/package.json +1 -1
package/README.md
CHANGED
@@ -242,6 +242,25 @@ With data `{ name: 'Good cop' }` (no color):
|
|
242
242
|
<span>Good cop</span>
|
243
243
|
```
|
244
244
|
|
245
|
+
### Conditional Attributes Block
|
246
|
+
|
247
|
+
Some attributes can't be evaluated or might break W3C validation if their value contains template syntax
|
248
|
+
(like braces or question marks).
|
249
|
+
|
250
|
+
To handle such cases, you can use the reserved `data-if` and `data-end` attributes
|
251
|
+
as a **conditional attribute block**.\
|
252
|
+
These control attributes will **not be rendered**.\
|
253
|
+
All attributes placed **between** `data-if` and `data-end` will be included in the output
|
254
|
+
**only if** the `data-if` condition evaluates to a [truthy](https://developer.mozilla.org/docs/Glossary/Truthy) value.
|
255
|
+
|
256
|
+
Example:
|
257
|
+
```html
|
258
|
+
<form data-if="{hasFileProperty}" enctype="multipart/form-data" method="post" data-end>
|
259
|
+
```
|
260
|
+
- `data-if` and `data-end` act as structural markers and are removed from the final output.
|
261
|
+
- `enctype="multipart/form-data"` and `method="post"` will appear only if the `hasFileProperty` function or property
|
262
|
+
of the current context returns `true`.
|
263
|
+
|
245
264
|
### Conditional Blocks
|
246
265
|
|
247
266
|
End your block expression with `?` to render the block only
|
package/cjs/template.js
CHANGED
@@ -615,12 +615,13 @@ class Template {
|
|
615
615
|
}
|
616
616
|
while (this.source[this.index] !== '>') {
|
617
617
|
// attribute name
|
618
|
-
const
|
618
|
+
const attributePosition = this.index;
|
619
619
|
while ((this.index < this.length) && !' =>\n\r\t\f'.includes(this.source[this.index]))
|
620
620
|
this.index++;
|
621
|
-
const attributeName = this.source.substring(
|
621
|
+
const attributeName = this.source.substring(attributePosition, this.index);
|
622
622
|
while (' \n\r\t\f'.includes(this.source[this.index]))
|
623
623
|
this.index++;
|
624
|
+
let attributeBlock = (attributeName[0] === 'd') && (attributeName === 'data-if') ? '' : undefined;
|
624
625
|
// attribute value
|
625
626
|
if (this.source[this.index] === '=') {
|
626
627
|
this.index++;
|
@@ -654,13 +655,18 @@ class Template {
|
|
654
655
|
if ((inLinkHRef || inScriptSrc || this.inLiteral) && (this.index > this.start)) {
|
655
656
|
this.sourceToTarget();
|
656
657
|
}
|
657
|
-
const
|
658
|
+
const valuePosition = this.index;
|
658
659
|
const shortQuote = !(quote.length - 1);
|
660
|
+
if (shortQuote && (attributeBlock !== undefined)) {
|
661
|
+
attributeBlock = this.target + this.source.substring(this.start, attributePosition);
|
662
|
+
this.start = this.index;
|
663
|
+
this.target = '';
|
664
|
+
}
|
659
665
|
while (this.index < this.length) {
|
660
666
|
const char = this.source[this.index];
|
661
667
|
// end of attribute value
|
662
668
|
if (shortQuote ? (char === quote) : quote.includes(char)) {
|
663
|
-
const attributeValue = this.source.substring(
|
669
|
+
const attributeValue = this.source.substring(valuePosition, this.index);
|
664
670
|
if (inInput && !hasTypeSubmit) {
|
665
671
|
hasTypeSubmit = (attributeChar === 't') && (attributeValue[0] === 's')
|
666
672
|
&& (attributeName === 'type') && (attributeValue === 'submit');
|
@@ -701,11 +707,30 @@ class Template {
|
|
701
707
|
this.index++;
|
702
708
|
}
|
703
709
|
}
|
704
|
-
else
|
705
|
-
this.onAttribute
|
710
|
+
else {
|
711
|
+
if (this.onAttribute)
|
712
|
+
this.onAttribute(attributeName, '');
|
713
|
+
if ((attributeName[0] === 'd') && (attributeName === 'data-end')) {
|
714
|
+
this.index = attributePosition;
|
715
|
+
this.sourceToTarget();
|
716
|
+
this.index += attributeName.length;
|
717
|
+
this.start = this.index;
|
718
|
+
}
|
719
|
+
}
|
706
720
|
// next attribute
|
707
721
|
while (' \n\r\t\f'.includes(this.source[this.index]))
|
708
722
|
this.index++;
|
723
|
+
if (attributeBlock !== undefined) {
|
724
|
+
if (!this.target) {
|
725
|
+
this.index = this.source.indexOf('data-end', this.index) + 8;
|
726
|
+
if (this.index < 8) {
|
727
|
+
throw 'Missing data-end matching data-if at position ' + attributePosition
|
728
|
+
+ ' into template file ' + this.filePath + node_path_1.sep + this.fileName;
|
729
|
+
}
|
730
|
+
}
|
731
|
+
this.start = this.index;
|
732
|
+
this.target = attributeBlock;
|
733
|
+
}
|
709
734
|
}
|
710
735
|
this.index++;
|
711
736
|
if (this.onTagOpened)
|
package/esm/template.js
CHANGED
@@ -612,12 +612,13 @@ export class Template {
|
|
612
612
|
}
|
613
613
|
while (this.source[this.index] !== '>') {
|
614
614
|
// attribute name
|
615
|
-
const
|
615
|
+
const attributePosition = this.index;
|
616
616
|
while ((this.index < this.length) && !' =>\n\r\t\f'.includes(this.source[this.index]))
|
617
617
|
this.index++;
|
618
|
-
const attributeName = this.source.substring(
|
618
|
+
const attributeName = this.source.substring(attributePosition, this.index);
|
619
619
|
while (' \n\r\t\f'.includes(this.source[this.index]))
|
620
620
|
this.index++;
|
621
|
+
let attributeBlock = (attributeName[0] === 'd') && (attributeName === 'data-if') ? '' : undefined;
|
621
622
|
// attribute value
|
622
623
|
if (this.source[this.index] === '=') {
|
623
624
|
this.index++;
|
@@ -651,13 +652,18 @@ export class Template {
|
|
651
652
|
if ((inLinkHRef || inScriptSrc || this.inLiteral) && (this.index > this.start)) {
|
652
653
|
this.sourceToTarget();
|
653
654
|
}
|
654
|
-
const
|
655
|
+
const valuePosition = this.index;
|
655
656
|
const shortQuote = !(quote.length - 1);
|
657
|
+
if (shortQuote && (attributeBlock !== undefined)) {
|
658
|
+
attributeBlock = this.target + this.source.substring(this.start, attributePosition);
|
659
|
+
this.start = this.index;
|
660
|
+
this.target = '';
|
661
|
+
}
|
656
662
|
while (this.index < this.length) {
|
657
663
|
const char = this.source[this.index];
|
658
664
|
// end of attribute value
|
659
665
|
if (shortQuote ? (char === quote) : quote.includes(char)) {
|
660
|
-
const attributeValue = this.source.substring(
|
666
|
+
const attributeValue = this.source.substring(valuePosition, this.index);
|
661
667
|
if (inInput && !hasTypeSubmit) {
|
662
668
|
hasTypeSubmit = (attributeChar === 't') && (attributeValue[0] === 's')
|
663
669
|
&& (attributeName === 'type') && (attributeValue === 'submit');
|
@@ -698,11 +704,30 @@ export class Template {
|
|
698
704
|
this.index++;
|
699
705
|
}
|
700
706
|
}
|
701
|
-
else
|
702
|
-
this.onAttribute
|
707
|
+
else {
|
708
|
+
if (this.onAttribute)
|
709
|
+
this.onAttribute(attributeName, '');
|
710
|
+
if ((attributeName[0] === 'd') && (attributeName === 'data-end')) {
|
711
|
+
this.index = attributePosition;
|
712
|
+
this.sourceToTarget();
|
713
|
+
this.index += attributeName.length;
|
714
|
+
this.start = this.index;
|
715
|
+
}
|
716
|
+
}
|
703
717
|
// next attribute
|
704
718
|
while (' \n\r\t\f'.includes(this.source[this.index]))
|
705
719
|
this.index++;
|
720
|
+
if (attributeBlock !== undefined) {
|
721
|
+
if (!this.target) {
|
722
|
+
this.index = this.source.indexOf('data-end', this.index) + 8;
|
723
|
+
if (this.index < 8) {
|
724
|
+
throw 'Missing data-end matching data-if at position ' + attributePosition
|
725
|
+
+ ' into template file ' + this.filePath + sep + this.fileName;
|
726
|
+
}
|
727
|
+
}
|
728
|
+
this.start = this.index;
|
729
|
+
this.target = attributeBlock;
|
730
|
+
}
|
706
731
|
}
|
707
732
|
this.index++;
|
708
733
|
if (this.onTagOpened)
|
package/package.json
CHANGED