@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 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 position = this.index;
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(position, this.index);
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 position = this.index;
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(position, this.index);
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 if (this.onAttribute)
705
- this.onAttribute(attributeName, '');
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 position = this.index;
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(position, this.index);
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 position = this.index;
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(position, this.index);
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 if (this.onAttribute)
702
- this.onAttribute(attributeName, '');
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
@@ -69,5 +69,5 @@
69
69
  "test": "test/test"
70
70
  },
71
71
  "types": "./esm/template.d.ts",
72
- "version": "0.0.39"
72
+ "version": "0.0.40"
73
73
  }