Glimmer: Improve whitespace handling (#6354)
* Improve curly and whitespace handling * Refactoring and clean up * Collapse elements with non-whitespace children * Clean selfClosing check in AST compare selfClosing tags can't be considered when using AST_COMPARE=1. The new AST may have a Glimmer component that has been collapsed, ie: <HelloWorld></HelloWorld> -> <HelloWorld /> These result in different ASTs and thereofre we need to clean the check that compares self-closing in the before and after ASTs Co-authored-by: Jamie White <jamie@jgwhite.co.uk> * Add istanbul ignore for ternaries in utilities * Improve handling around whitespace near elements and block statements * Update tests after rebasing * Fix CHANGELOG.unreleased.md after rebase * Tweak regex around leading and trialing line beraks and update test Co-authored-by: FabHof <35104465+FabHof@users.noreply.github.com> * Extract attribute value from concat nodemaster
parent
e4ab962a6d
commit
a7cae47cdf
|
@ -1037,7 +1037,50 @@ class A {
|
|||
}}
|
||||
```
|
||||
|
||||
[#5682]: https://github.com/prettier/prettier/pull/5682
|
||||
#### Handlebars: Fix handling of whitespace and line breaks ([#6354] by [@chadian])
|
||||
|
||||
This fixes a variety of whitespace and line break usecases within handlebars and Glimmer templates.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```hbs
|
||||
// Input
|
||||
<SomeComponent />{{name}}
|
||||
|
||||
Some sentence with {{dynamic}} expressions.
|
||||
|
||||
|
||||
|
||||
sometimes{{nogaps}}areimportant<Hello></Hello>
|
||||
{{name}} is your name
|
||||
|
||||
// Output (Prettier stable)
|
||||
<SomeComponent />
|
||||
{{name}}
|
||||
Some sentence with
|
||||
{{dynamic}}
|
||||
expressions.
|
||||
|
||||
|
||||
|
||||
sometimes
|
||||
{{nogaps}}
|
||||
areimportant
|
||||
<Hello />
|
||||
{{name}}
|
||||
is your name
|
||||
|
||||
// Output (Prettier master)
|
||||
<SomeComponent />{{name}}
|
||||
|
||||
Some sentence with {{dynamic}} expressions.
|
||||
|
||||
|
||||
|
||||
sometimes{{nogaps}}areimportant
|
||||
<Hello />
|
||||
{{name}} is your name
|
||||
```
|
||||
|
||||
[#5910]: https://github.com/prettier/prettier/pull/5910
|
||||
[#6033]: https://github.com/prettier/prettier/pull/6033
|
||||
[#6186]: https://github.com/prettier/prettier/pull/6186
|
||||
|
@ -1087,3 +1130,4 @@ class A {
|
|||
[@squidfunk]: https://github.com/squidfunk
|
||||
[@vjeux]: https://github.com/vjeux
|
||||
[@selvazhagan]: https://github.com/selvazhagan
|
||||
[@chadian]: https://github.com/chadian
|
||||
|
|
|
@ -43,19 +43,11 @@ function printChildren(path, options, print) {
|
|||
const isWhitespace = isWhitespaceNode(childNode);
|
||||
|
||||
if (isWhitespace && isLastNodeInMultiNodeList) {
|
||||
return concat([print(childPath, options, print)]);
|
||||
} else if (
|
||||
isFirstNode ||
|
||||
isPreviousNodeOfSomeType(childPath, [
|
||||
"ElementNode",
|
||||
"CommentStatement",
|
||||
"MustacheCommentStatement",
|
||||
"BlockStatement"
|
||||
])
|
||||
) {
|
||||
return print(childPath, options, print);
|
||||
} else if (isFirstNode) {
|
||||
return concat([softline, print(childPath, options, print)]);
|
||||
}
|
||||
return concat([print(childPath, options, print)]);
|
||||
return print(childPath, options, print);
|
||||
}, "children")
|
||||
);
|
||||
}
|
||||
|
@ -72,9 +64,7 @@ function print(path, options, print) {
|
|||
case "Block":
|
||||
case "Program":
|
||||
case "Template": {
|
||||
return group(
|
||||
join(softline, path.map(print, "body").filter(text => text !== ""))
|
||||
);
|
||||
return group(concat(path.map(print, "body").filter(text => text !== "")));
|
||||
}
|
||||
case "ElementNode": {
|
||||
const tagFirstChar = n.tag[0];
|
||||
|
@ -82,8 +72,14 @@ function print(path, options, print) {
|
|||
const isGlimmerComponent =
|
||||
tagFirstChar.toUpperCase() === tagFirstChar || isLocal;
|
||||
const hasChildren = n.children.length > 0;
|
||||
|
||||
const hasNonWhitespaceChildren = n.children.some(
|
||||
n => !isWhitespaceNode(n)
|
||||
);
|
||||
|
||||
const isVoid =
|
||||
(isGlimmerComponent && !hasChildren) || voidTags.indexOf(n.tag) !== -1;
|
||||
(isGlimmerComponent && (!hasChildren || !hasNonWhitespaceChildren)) ||
|
||||
voidTags.indexOf(n.tag) !== -1;
|
||||
const closeTagForNoBreak = isVoid ? concat([" />", softline]) : ">";
|
||||
const closeTagForBreak = isVoid ? "/>" : ">";
|
||||
const getParams = (path, print) =>
|
||||
|
@ -100,6 +96,8 @@ function print(path, options, print) {
|
|||
])
|
||||
);
|
||||
|
||||
const nextNode = getNextNode(path);
|
||||
|
||||
return concat([
|
||||
group(
|
||||
concat([
|
||||
|
@ -111,13 +109,18 @@ function print(path, options, print) {
|
|||
ifBreak(closeTagForBreak, closeTagForNoBreak)
|
||||
])
|
||||
),
|
||||
group(
|
||||
concat([
|
||||
indent(printChildren(path, options, print)),
|
||||
ifBreak(hasChildren ? hardline : "", ""),
|
||||
!isVoid ? concat(["</", n.tag, ">"]) : ""
|
||||
])
|
||||
)
|
||||
!isVoid
|
||||
? group(
|
||||
concat([
|
||||
hasNonWhitespaceChildren
|
||||
? indent(printChildren(path, options, print))
|
||||
: "",
|
||||
ifBreak(hasChildren ? hardline : "", ""),
|
||||
concat(["</", n.tag, ">"])
|
||||
])
|
||||
)
|
||||
: "",
|
||||
nextNode && nextNode.type === "ElementNode" ? hardline : ""
|
||||
]);
|
||||
}
|
||||
case "BlockStatement": {
|
||||
|
@ -156,6 +159,7 @@ function print(path, options, print) {
|
|||
const hasNonWhitespaceChildren = n.program.body.some(
|
||||
n => !isWhitespaceNode(n)
|
||||
);
|
||||
|
||||
return concat([
|
||||
printOpenBlock(path, print),
|
||||
group(
|
||||
|
@ -196,7 +200,9 @@ function print(path, options, print) {
|
|||
return concat([n.name]);
|
||||
}
|
||||
const value = path.call(print, "value");
|
||||
const quotedValue = isText ? printStringLiteral(value, options) : value;
|
||||
const quotedValue = isText
|
||||
? printStringLiteral(value.parts.join(), options)
|
||||
: value;
|
||||
return concat([n.name, "=", quotedValue]);
|
||||
}
|
||||
case "ConcatStatement": {
|
||||
|
@ -222,25 +228,54 @@ function print(path, options, print) {
|
|||
return concat([n.key, "=", path.call(print, "value")]);
|
||||
}
|
||||
case "TextNode": {
|
||||
const maxLineBreaksToPreserve = 2;
|
||||
const isFirstElement = !getPreviousNode(path);
|
||||
const isLastElement = !getNextNode(path);
|
||||
const isWhitespaceOnly = !/\S/.test(n.chars);
|
||||
const lineBreaksCount = countNewLines(n.chars);
|
||||
const hasBlockParent = path.getParentNode(0).type === "Block";
|
||||
const hasElementParent = path.getParentNode(0).type === "ElementNode";
|
||||
const hasTemplateParent = path.getParentNode(0).type === "Template";
|
||||
|
||||
let leadingLineBreaksCount = countLeadingNewLines(n.chars);
|
||||
let trailingLineBreaksCount = countTrailingNewLines(n.chars);
|
||||
|
||||
if (
|
||||
(isFirstElement || isLastElement) &&
|
||||
isWhitespaceOnly &&
|
||||
isPreviousNodeOfSomeType(path, ["MustacheStatement", "TextNode"])
|
||||
(hasBlockParent || hasElementParent || hasTemplateParent)
|
||||
) {
|
||||
return " ";
|
||||
return "";
|
||||
}
|
||||
|
||||
if (isWhitespaceOnly && lineBreaksCount) {
|
||||
leadingLineBreaksCount = Math.min(
|
||||
lineBreaksCount,
|
||||
maxLineBreaksToPreserve
|
||||
);
|
||||
trailingLineBreaksCount = 0;
|
||||
} else {
|
||||
if (
|
||||
isNextNodeOfType(path, "ElementNode") ||
|
||||
isNextNodeOfType(path, "BlockStatement")
|
||||
) {
|
||||
trailingLineBreaksCount = Math.max(trailingLineBreaksCount, 1);
|
||||
}
|
||||
|
||||
if (
|
||||
isPreviousNodeOfSomeType(path, ["ElementNode"]) ||
|
||||
isPreviousNodeOfSomeType(path, ["BlockStatement"])
|
||||
) {
|
||||
leadingLineBreaksCount = Math.max(leadingLineBreaksCount, 1);
|
||||
}
|
||||
}
|
||||
|
||||
let leadingSpace = "";
|
||||
let trailingSpace = "";
|
||||
|
||||
if (isNextNodeOfType(path, "MustacheStatement")) {
|
||||
trailingSpace = " ";
|
||||
}
|
||||
|
||||
// preserve a space inside of an attribute node where whitespace present, when next to mustache statement.
|
||||
// preserve a space inside of an attribute node where whitespace present,
|
||||
// when next to mustache statement.
|
||||
const inAttrNode = path.stack.indexOf("attributes") >= 0;
|
||||
|
||||
if (inAttrNode) {
|
||||
const parentNode = path.getParentNode(0);
|
||||
const isConcat = parentNode.type === "ConcatStatement";
|
||||
|
@ -262,10 +297,41 @@ function print(path, options, print) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
trailingLineBreaksCount === 0 &&
|
||||
isNextNodeOfType(path, "MustacheStatement")
|
||||
) {
|
||||
trailingSpace = " ";
|
||||
}
|
||||
|
||||
if (
|
||||
leadingLineBreaksCount === 0 &&
|
||||
isPreviousNodeOfSomeType(path, ["MustacheStatement"])
|
||||
) {
|
||||
leadingSpace = " ";
|
||||
}
|
||||
|
||||
if (isFirstElement) {
|
||||
leadingLineBreaksCount = 0;
|
||||
leadingSpace = "";
|
||||
}
|
||||
|
||||
if (isLastElement) {
|
||||
trailingLineBreaksCount = 0;
|
||||
trailingSpace = "";
|
||||
}
|
||||
}
|
||||
return n.chars
|
||||
.replace(/^\s+/, leadingSpace)
|
||||
.replace(/\s+$/, trailingSpace);
|
||||
|
||||
return concat(
|
||||
[
|
||||
...generateHardlines(leadingLineBreaksCount, maxLineBreaksToPreserve),
|
||||
n.chars
|
||||
.replace(/^[\s ]+/g, leadingSpace)
|
||||
.replace(/[\s ]+$/, trailingSpace),
|
||||
...generateHardlines(trailingLineBreaksCount, maxLineBreaksToPreserve)
|
||||
].filter(Boolean)
|
||||
);
|
||||
}
|
||||
case "MustacheCommentStatement": {
|
||||
const dashes = n.value.indexOf("}}") > -1 ? "--" : "";
|
||||
|
@ -405,7 +471,7 @@ function getPreviousNode(path) {
|
|||
const node = path.getValue();
|
||||
const parentNode = path.getParentNode(0);
|
||||
|
||||
const children = parentNode.children;
|
||||
const children = parentNode.children || parentNode.body;
|
||||
if (children) {
|
||||
const nodeIndex = children.indexOf(node);
|
||||
if (nodeIndex > 0) {
|
||||
|
@ -419,7 +485,7 @@ function getNextNode(path) {
|
|||
const node = path.getValue();
|
||||
const parentNode = path.getParentNode(0);
|
||||
|
||||
const children = parentNode.children;
|
||||
const children = parentNode.children || parentNode.body;
|
||||
if (children) {
|
||||
const nodeIndex = children.indexOf(node);
|
||||
if (nodeIndex < children.length) {
|
||||
|
@ -445,6 +511,7 @@ function isNextNodeOfType(path, type) {
|
|||
|
||||
function clean(ast, newObj) {
|
||||
delete newObj.loc;
|
||||
delete newObj.selfClosing;
|
||||
|
||||
// (Glimmer/HTML) ignore TextNode whitespace
|
||||
if (ast.type === "TextNode") {
|
||||
|
@ -455,6 +522,30 @@ function clean(ast, newObj) {
|
|||
}
|
||||
}
|
||||
|
||||
function countNewLines(string) {
|
||||
/* istanbul ignore next */
|
||||
string = typeof string === "string" ? string : "";
|
||||
return string.split("\n").length - 1;
|
||||
}
|
||||
|
||||
function countLeadingNewLines(string) {
|
||||
/* istanbul ignore next */
|
||||
string = typeof string === "string" ? string : "";
|
||||
const newLines = (string.match(/^([^\S\r\n]*[\r\n])+/g) || [])[0] || "";
|
||||
return countNewLines(newLines);
|
||||
}
|
||||
|
||||
function countTrailingNewLines(string) {
|
||||
/* istanbul ignore next */
|
||||
string = typeof string === "string" ? string : "";
|
||||
const newLines = (string.match(/([\r\n][^\S\r\n]*)+$/g) || [])[0] || "";
|
||||
return countNewLines(newLines);
|
||||
}
|
||||
|
||||
function generateHardlines(number = 0, max = 0) {
|
||||
return new Array(Math.min(number, max)).fill(hardline);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
print,
|
||||
massageAstNode: clean
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<SomeComponent />
|
||||
{{name}}
|
||||
|
||||
|
||||
|
||||
Some sentence with {{dynamic}} expressions.
|
||||
|
||||
sometimes{{nogaps}}areimportant<Hello></Hello>
|
||||
|
||||
|
||||
{{name}} is your name
|
||||
|
||||
|
||||
{{#block}}
|
||||
{{/block}}
|
||||
|
||||
|
||||
{{#block}}
|
||||
some {{text}}
|
||||
{{/block}}
|
||||
|
||||
{{#block}}
|
||||
|
||||
some {{text}}
|
||||
{{/block}}
|
||||
|
||||
<HelloWorld>
|
||||
</HelloWorld>
|
||||
|
||||
<HelloWorld>
|
||||
some {{text}}
|
||||
</HelloWorld>
|
||||
|
||||
<HelloWorld>
|
||||
|
||||
some {{text}}
|
||||
</HelloWorld>
|
||||
|
||||
<div class="a list of classes">
|
||||
</div>
|
||||
|
||||
<div class="a list of classes">
|
||||
|
||||
</div>
|
|
@ -28,6 +28,7 @@ printWidth: 80
|
|||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<div class="{{hello}} {{world}}"></div>
|
||||
================================================================================
|
||||
`;
|
||||
|
@ -61,6 +62,7 @@ singleQuote: true
|
|||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<div class="{{hello}} {{world}}"></div>
|
||||
================================================================================
|
||||
`;
|
||||
|
@ -99,28 +101,33 @@ printWidth: 80
|
|||
|
||||
=====================================output=====================================
|
||||
<UserGreeting @name="Ricardo" @greeting="Olá" />
|
||||
{{@greeting}}
|
||||
,
|
||||
{{@name}}
|
||||
!
|
||||
{{@greeting}}, {{@name}}!
|
||||
|
||||
<div>
|
||||
<UserGreeting
|
||||
@aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Form as |f|>
|
||||
<f.input @title="hello" />
|
||||
<f.input>
|
||||
hello
|
||||
</f.input>
|
||||
</Form>
|
||||
|
||||
<this.label @title="hello" />
|
||||
|
||||
<button onclick={{action next}}>
|
||||
Next
|
||||
</button>
|
||||
|
||||
<button disabled class="disabled"></button>
|
||||
|
||||
<button disabled="disabled" class="disabled"></button>
|
||||
|
||||
<img alt="" />
|
||||
|
||||
<div ...attributes>
|
||||
Hello
|
||||
</div>
|
||||
|
@ -162,28 +169,33 @@ singleQuote: true
|
|||
|
||||
=====================================output=====================================
|
||||
<UserGreeting @name='Ricardo' @greeting='Olá' />
|
||||
{{@greeting}}
|
||||
,
|
||||
{{@name}}
|
||||
!
|
||||
{{@greeting}}, {{@name}}!
|
||||
|
||||
<div>
|
||||
<UserGreeting
|
||||
@aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Form as |f|>
|
||||
<f.input @title='hello' />
|
||||
<f.input>
|
||||
hello
|
||||
</f.input>
|
||||
</Form>
|
||||
|
||||
<this.label @title='hello' />
|
||||
|
||||
<button onclick={{action next}}>
|
||||
Next
|
||||
</button>
|
||||
|
||||
<button disabled class='disabled'></button>
|
||||
|
||||
<button disabled='disabled' class='disabled'></button>
|
||||
|
||||
<img alt='' />
|
||||
|
||||
<div ...attributes>
|
||||
Hello
|
||||
</div>
|
||||
|
@ -264,6 +276,7 @@ printWidth: 80
|
|||
<h2>
|
||||
By {{author.name}}
|
||||
</h2>
|
||||
|
||||
<div class="body">
|
||||
{{body}}
|
||||
</div>
|
||||
|
@ -295,6 +308,7 @@ singleQuote: true
|
|||
<h2>
|
||||
By {{author.name}}
|
||||
</h2>
|
||||
|
||||
<div class='body'>
|
||||
{{body}}
|
||||
</div>
|
||||
|
|
|
@ -63,11 +63,13 @@ printWidth: 80
|
|||
{{#block param hashKey=hashValue as |blockParam|}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block
|
||||
almost80CharacterLongPositionalParamThatIsFirstAlmost80Chars
|
||||
helloWorldParam
|
||||
key=here
|
||||
}}{{/block}}
|
||||
|
||||
{{#block
|
||||
param
|
||||
param
|
||||
|
@ -80,6 +82,7 @@ printWidth: 80
|
|||
}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block
|
||||
param
|
||||
param
|
||||
|
@ -93,6 +96,7 @@ printWidth: 80
|
|||
}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block
|
||||
param
|
||||
param
|
||||
|
@ -110,6 +114,7 @@ printWidth: 80
|
|||
}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block
|
||||
hashKey=HashValue
|
||||
hashKey=hashValue
|
||||
|
@ -119,27 +124,33 @@ printWidth: 80
|
|||
}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block}}
|
||||
{{#block}}
|
||||
hello
|
||||
{{/block}}
|
||||
{{/block}}
|
||||
|
||||
{{#block}}
|
||||
{{#block param}}
|
||||
hello
|
||||
{{/block}}
|
||||
{{/block}}
|
||||
|
||||
{{#block param}}
|
||||
{{#block param}}
|
||||
hello
|
||||
{{/block}}
|
||||
{{/block}}
|
||||
|
||||
{{#block}}
|
||||
hello
|
||||
{{/block}}
|
||||
|
||||
<MyComponent as |firstName|>
|
||||
{{firstName}}
|
||||
</MyComponent>
|
||||
|
||||
<MyComponent as |firstName lastName|>
|
||||
{{firstName}} {{lastName}}
|
||||
</MyComponent>
|
||||
|
@ -210,11 +221,13 @@ singleQuote: true
|
|||
{{#block param hashKey=hashValue as |blockParam|}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block
|
||||
almost80CharacterLongPositionalParamThatIsFirstAlmost80Chars
|
||||
helloWorldParam
|
||||
key=here
|
||||
}}{{/block}}
|
||||
|
||||
{{#block
|
||||
param
|
||||
param
|
||||
|
@ -227,6 +240,7 @@ singleQuote: true
|
|||
}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block
|
||||
param
|
||||
param
|
||||
|
@ -240,6 +254,7 @@ singleQuote: true
|
|||
}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block
|
||||
param
|
||||
param
|
||||
|
@ -257,6 +272,7 @@ singleQuote: true
|
|||
}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block
|
||||
hashKey=HashValue
|
||||
hashKey=hashValue
|
||||
|
@ -266,27 +282,33 @@ singleQuote: true
|
|||
}}
|
||||
Hello
|
||||
{{/block}}
|
||||
|
||||
{{#block}}
|
||||
{{#block}}
|
||||
hello
|
||||
{{/block}}
|
||||
{{/block}}
|
||||
|
||||
{{#block}}
|
||||
{{#block param}}
|
||||
hello
|
||||
{{/block}}
|
||||
{{/block}}
|
||||
|
||||
{{#block param}}
|
||||
{{#block param}}
|
||||
hello
|
||||
{{/block}}
|
||||
{{/block}}
|
||||
|
||||
{{#block}}
|
||||
hello
|
||||
{{/block}}
|
||||
|
||||
<MyComponent as |firstName|>
|
||||
{{firstName}}
|
||||
</MyComponent>
|
||||
|
||||
<MyComponent as |firstName lastName|>
|
||||
{{firstName}} {{lastName}}
|
||||
</MyComponent>
|
||||
|
@ -471,6 +493,7 @@ printWidth: 80
|
|||
Go to bed!
|
||||
{{/if}}
|
||||
</h1>
|
||||
|
||||
<h2>
|
||||
{{#if a}}
|
||||
A
|
||||
|
@ -478,6 +501,7 @@ printWidth: 80
|
|||
B
|
||||
{{/if}}
|
||||
</h2>
|
||||
|
||||
{{#if a}}
|
||||
b
|
||||
{{else if c}}
|
||||
|
@ -485,6 +509,7 @@ printWidth: 80
|
|||
{{else}}
|
||||
e
|
||||
{{/if}}
|
||||
|
||||
{{#if a}}
|
||||
b
|
||||
{{else if c}}
|
||||
|
@ -496,6 +521,7 @@ printWidth: 80
|
|||
{{/if}}
|
||||
e
|
||||
{{/if}}
|
||||
|
||||
{{#if a}}
|
||||
b
|
||||
{{else if c}}
|
||||
|
@ -507,6 +533,7 @@ printWidth: 80
|
|||
{{else}}
|
||||
j
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
{{#if a}}
|
||||
b
|
||||
|
@ -516,6 +543,7 @@ printWidth: 80
|
|||
e
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
{{#if a}}
|
||||
|
@ -527,6 +555,7 @@ printWidth: 80
|
|||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if a}}
|
||||
b
|
||||
{{else}}
|
||||
|
@ -534,6 +563,7 @@ printWidth: 80
|
|||
e
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if a}}
|
||||
{{#if b}}
|
||||
ab
|
||||
|
@ -541,6 +571,7 @@ printWidth: 80
|
|||
ac
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if a}}
|
||||
a
|
||||
<div>
|
||||
|
@ -684,6 +715,7 @@ singleQuote: true
|
|||
Go to bed!
|
||||
{{/if}}
|
||||
</h1>
|
||||
|
||||
<h2>
|
||||
{{#if a}}
|
||||
A
|
||||
|
@ -691,6 +723,7 @@ singleQuote: true
|
|||
B
|
||||
{{/if}}
|
||||
</h2>
|
||||
|
||||
{{#if a}}
|
||||
b
|
||||
{{else if c}}
|
||||
|
@ -698,6 +731,7 @@ singleQuote: true
|
|||
{{else}}
|
||||
e
|
||||
{{/if}}
|
||||
|
||||
{{#if a}}
|
||||
b
|
||||
{{else if c}}
|
||||
|
@ -709,6 +743,7 @@ singleQuote: true
|
|||
{{/if}}
|
||||
e
|
||||
{{/if}}
|
||||
|
||||
{{#if a}}
|
||||
b
|
||||
{{else if c}}
|
||||
|
@ -720,6 +755,7 @@ singleQuote: true
|
|||
{{else}}
|
||||
j
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
{{#if a}}
|
||||
b
|
||||
|
@ -729,6 +765,7 @@ singleQuote: true
|
|||
e
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
{{#if a}}
|
||||
|
@ -740,6 +777,7 @@ singleQuote: true
|
|||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if a}}
|
||||
b
|
||||
{{else}}
|
||||
|
@ -747,6 +785,7 @@ singleQuote: true
|
|||
e
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if a}}
|
||||
{{#if b}}
|
||||
ab
|
||||
|
@ -754,6 +793,7 @@ singleQuote: true
|
|||
ac
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if a}}
|
||||
a
|
||||
<div>
|
||||
|
|
|
@ -30,11 +30,13 @@ printWidth: 80
|
|||
{{#if @foo}}
|
||||
Foo
|
||||
{{/if}}
|
||||
|
||||
{{! Bar }}
|
||||
{{#if @bar}}
|
||||
Bar
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="entry">
|
||||
{{! This comment will not be in the output }}
|
||||
{{!-- This comment as }} and will not be in the output --}}
|
||||
|
|
|
@ -30,6 +30,7 @@ printWidth: 80
|
|||
<div class="hello {{if goodbye true}}">
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="hello
|
||||
{{if goodbye true}}
|
||||
|
@ -44,7 +45,9 @@ printWidth: 80
|
|||
>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<a href="/{{url}}/{{url}}"></a>
|
||||
|
||||
<div class="class-a{{myClass}}"></div>
|
||||
<div class="class-b {{myClass}}"></div>
|
||||
<div class="{{myClass}}class-c"></div>
|
||||
|
@ -89,6 +92,7 @@ singleQuote: true
|
|||
<div class="hello {{if goodbye true}}">
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="hello
|
||||
{{if goodbye true}}
|
||||
|
@ -103,7 +107,9 @@ singleQuote: true
|
|||
>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<a href="/{{url}}/{{url}}"></a>
|
||||
|
||||
<div class="class-a{{myClass}}"></div>
|
||||
<div class="class-b {{myClass}}"></div>
|
||||
<div class="{{myClass}}class-c"></div>
|
||||
|
|
|
@ -47,29 +47,37 @@ printWidth: 80
|
|||
<div class="attribute" {{modifier}} {{! comment}}>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div>
|
||||
hi
|
||||
</div>
|
||||
|
||||
<div>
|
||||
A long enough string to trigger a line break that would prevent wrapping.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
A long enough string to trigger a line break that would prevent wrapping more.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
A long enough string to trigger a line break that would prevent wrapping more and more.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{#block}}
|
||||
{{hello}}
|
||||
{{/block}}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{hello}}
|
||||
</div>
|
||||
|
||||
<div></div>
|
||||
<img />
|
||||
================================================================================
|
||||
|
@ -123,29 +131,37 @@ singleQuote: true
|
|||
<div class='attribute' {{modifier}} {{! comment}}>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div>
|
||||
hi
|
||||
</div>
|
||||
|
||||
<div>
|
||||
A long enough string to trigger a line break that would prevent wrapping.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
A long enough string to trigger a line break that would prevent wrapping more.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
A long enough string to trigger a line break that would prevent wrapping more and more.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{#block}}
|
||||
{{hello}}
|
||||
{{/block}}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{hello}}
|
||||
</div>
|
||||
|
||||
<div></div>
|
||||
<img />
|
||||
================================================================================
|
||||
|
|
|
@ -26,6 +26,7 @@ printWidth: 80
|
|||
<div {{hello param hash=key}} {{goodbye param}}>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div
|
||||
{{hello
|
||||
param
|
||||
|
@ -44,6 +45,7 @@ printWidth: 80
|
|||
>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div
|
||||
{{hello
|
||||
hashPair=value
|
||||
|
@ -55,6 +57,7 @@ printWidth: 80
|
|||
>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div
|
||||
{{hello
|
||||
param
|
||||
|
@ -100,6 +103,7 @@ singleQuote: true
|
|||
<div {{hello param hash=key}} {{goodbye param}}>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div
|
||||
{{hello
|
||||
param
|
||||
|
@ -118,6 +122,7 @@ singleQuote: true
|
|||
>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div
|
||||
{{hello
|
||||
hashPair=value
|
||||
|
@ -129,6 +134,7 @@ singleQuote: true
|
|||
>
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div
|
||||
{{hello
|
||||
param
|
||||
|
|
|
@ -78,12 +78,14 @@ printWidth: 80
|
|||
|
||||
=====================================output=====================================
|
||||
<p>
|
||||
Welcome to the<strong>
|
||||
Welcome to the
|
||||
<strong>
|
||||
Ember.js Guides
|
||||
</strong>
|
||||
.
|
||||
This documentation will take you from total beginner to Ember expert.
|
||||
</p>
|
||||
|
||||
{{! newlines text }}
|
||||
<div>
|
||||
hi
|
||||
|
@ -95,39 +97,52 @@ printWidth: 80
|
|||
|
||||
are you fine today?
|
||||
</div>
|
||||
|
||||
{{! newlines text spaced }}
|
||||
<div>
|
||||
space above
|
||||
|
||||
space below
|
||||
</div>
|
||||
|
||||
{{! newlines elems spaced }}
|
||||
<div>
|
||||
<span>
|
||||
space above
|
||||
</span>
|
||||
|
||||
<span>
|
||||
space below
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{! newlines mixed }}
|
||||
<div>
|
||||
hi<span>
|
||||
hi
|
||||
<span>
|
||||
there
|
||||
</span>
|
||||
|
||||
how
|
||||
|
||||
are<strong>
|
||||
are
|
||||
<strong>
|
||||
you
|
||||
</strong>
|
||||
|
||||
are you fine today?
|
||||
</div>
|
||||
|
||||
{{! newlines elems }}
|
||||
<div>
|
||||
<div>
|
||||
<div></div>
|
||||
</div>
|
||||
hi<div></div>
|
||||
|
||||
hi
|
||||
|
||||
<div></div>
|
||||
|
||||
<Big />
|
||||
</div>
|
||||
================================================================================
|
||||
|
|
|
@ -63,6 +63,7 @@ printWidth: 80
|
|||
)
|
||||
}}
|
||||
></div>
|
||||
|
||||
{{#block
|
||||
(concat
|
||||
(service)
|
||||
|
@ -84,6 +85,7 @@ printWidth: 80
|
|||
hashPair=(does not need a line break due to being under 80 chars long)
|
||||
)
|
||||
}}{{/block}}
|
||||
|
||||
{{foobar-sub-component/foobar-foo
|
||||
hook="stringLiteral"
|
||||
foo=(t
|
||||
|
@ -160,6 +162,7 @@ singleQuote: true
|
|||
)
|
||||
}}
|
||||
></div>
|
||||
|
||||
{{#block
|
||||
(concat
|
||||
(service)
|
||||
|
@ -181,6 +184,7 @@ singleQuote: true
|
|||
hashPair=(does not need a line break due to being under 80 chars long)
|
||||
)
|
||||
}}{{/block}}
|
||||
|
||||
{{foobar-sub-component/foobar-foo
|
||||
hook='stringLiteral'
|
||||
foo=(t
|
||||
|
|
|
@ -157,6 +157,34 @@ printWidth: 80
|
|||
<div>
|
||||
Some text that would need to wrap on to a new line in order to display correctly and nicely
|
||||
</div>
|
||||
|
||||
{{! Wrapping tags }}
|
||||
<div>
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
</div>
|
||||
|
||||
{{! Wrapping tags }}
|
||||
<div>
|
||||
<first>
|
||||
|
@ -178,121 +206,125 @@ printWidth: 80
|
|||
f
|
||||
</first>
|
||||
</div>
|
||||
{{! Wrapping tags }}
|
||||
<div>
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
</div>
|
||||
|
||||
{{! Wrapping tags }}
|
||||
<div>
|
||||
<first>
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
</first>
|
||||
|
||||
<first>
|
||||
f
|
||||
</first>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
before<div>
|
||||
before
|
||||
<div>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at mollis lorem.
|
||||
</div>
|
||||
after
|
||||
</div>
|
||||
|
||||
<div>
|
||||
before{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{stuff}{stuff}{stuff}after{stuff}after
|
||||
</div>
|
||||
|
||||
<div>
|
||||
before {{stuff}}after {{stuff}}after {{stuff}}after {{stuff}}after {{stuff
|
||||
}}after {{stuff}} {{stuff}} {{stuff}}after {{stuff}}after
|
||||
before {{stuff}} after {{stuff}} after {{stuff}} after {{stuff}} after {{stuff
|
||||
}} after {{stuff}} {{stuff}} {{stuff}} after {{stuff}} after
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Please state your<b>
|
||||
Please state your
|
||||
<b>
|
||||
name
|
||||
</b>
|
||||
and<b>
|
||||
and
|
||||
<b>
|
||||
occupation
|
||||
</b>
|
||||
for the board of<b>
|
||||
for the board of
|
||||
<b>
|
||||
school
|
||||
</b>
|
||||
directors.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
First second third<div
|
||||
First second third
|
||||
<div
|
||||
attr="a very long string attribute that will overflow because it is very long"
|
||||
>
|
||||
Something
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
First
|
||||
</div>
|
||||
Second<div>
|
||||
Second
|
||||
<div>
|
||||
Third
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
First<div>
|
||||
First
|
||||
<div>
|
||||
Second
|
||||
</div>
|
||||
Third
|
||||
</div>
|
||||
|
||||
{{! leading whitespace }}
|
||||
<div>
|
||||
First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth Thirteenth Fourteenth
|
||||
</div>
|
||||
|
||||
{{! trailing whitespace }}
|
||||
<div>
|
||||
First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth Thirteenth Fourteenth
|
||||
</div>
|
||||
|
||||
{{! no leading or trailing whitespace }}
|
||||
<div>
|
||||
First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth Thirteenth Fourteenth
|
||||
</div>
|
||||
|
||||
{{! translation leave text around tag }}
|
||||
<div>
|
||||
<span>
|
||||
First
|
||||
</span>
|
||||
,
|
||||
(<span>
|
||||
(
|
||||
<span>
|
||||
Second
|
||||
</span>
|
||||
)
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>
|
||||
First second third fourth fifth sixth seventh
|
||||
</span>
|
||||
,
|
||||
(<span>
|
||||
(
|
||||
<span>
|
||||
Second
|
||||
</span>
|
||||
)
|
||||
</div>
|
||||
|
||||
{{! this really should split across lines }}
|
||||
<div>
|
||||
before{{stuff}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff
|
||||
}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff
|
||||
}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff}}after
|
||||
</div>
|
||||
|
||||
{{! solitary whitespace }}
|
||||
<div
|
||||
first="first"
|
||||
|
@ -302,30 +334,36 @@ printWidth: 80
|
|||
fifth="fifth"
|
||||
sixth="sixth"
|
||||
>
|
||||
|
||||
</div>
|
||||
|
||||
{{! whitespace on newline }}
|
||||
<div>
|
||||
<div>
|
||||
First
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Second
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Third
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{! around multiline element }}
|
||||
<div>
|
||||
Before<div>
|
||||
Before
|
||||
<div>
|
||||
{"Enough text to make this element wrap on to multiple lines when formatting"}
|
||||
</div>
|
||||
After
|
||||
</div>
|
||||
|
||||
{{! around multiline element second pass }}
|
||||
<div>
|
||||
Before{" "}<div>
|
||||
Before{" "}
|
||||
<div>
|
||||
{
|
||||
"Enough text to make this element wrap on to multiple lines when formatting"
|
||||
}
|
||||
|
@ -333,34 +371,45 @@ printWidth: 80
|
|||
{" "}
|
||||
After
|
||||
</div>
|
||||
|
||||
{{! dont preserve blank lines when contains text }}
|
||||
<div>
|
||||
<div>
|
||||
Zeroth
|
||||
</div>
|
||||
|
||||
<div>
|
||||
First
|
||||
</div>
|
||||
|
||||
Second
|
||||
</div>
|
||||
|
||||
{{! multiple expressions }}
|
||||
<div>
|
||||
{{header}} {{body}} {{footer}}
|
||||
{{header}}
|
||||
{{body}}
|
||||
{{footer}}
|
||||
</div>
|
||||
|
||||
{{! single expression child tags }}
|
||||
<div>
|
||||
You currently have<strong>
|
||||
You currently have
|
||||
<strong>
|
||||
{{dashboardStr}}
|
||||
</strong>
|
||||
and<strong>
|
||||
and
|
||||
<strong>
|
||||
{{userStr}}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
{{! expression does not break }}
|
||||
<div>
|
||||
texty text text text text text text text text text text text {{this.props.type
|
||||
}}
|
||||
</div>
|
||||
|
||||
// FIXME
|
||||
================================================================================
|
||||
`;
|
||||
|
|
|
@ -36,10 +36,12 @@ printWidth: 40
|
|||
=====================================output=====================================
|
||||
{{! after }}
|
||||
<span>
|
||||
foo<span>
|
||||
foo
|
||||
<span>
|
||||
bar
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{{! before }}
|
||||
<span>
|
||||
<span>
|
||||
|
@ -47,17 +49,21 @@ printWidth: 40
|
|||
</span>
|
||||
foo
|
||||
</span>
|
||||
|
||||
{{! within }}
|
||||
<span>
|
||||
foo<span>
|
||||
foo
|
||||
<span>
|
||||
bar
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{{! break components }}
|
||||
<div>
|
||||
<SuperSelect>
|
||||
<p>
|
||||
foo<span>
|
||||
foo
|
||||
<span>
|
||||
bar bar bar
|
||||
</span>
|
||||
</p>
|
||||
|
@ -73,10 +79,13 @@ printWidth: 40
|
|||
nope
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
hello<strong>
|
||||
hello
|
||||
<strong>
|
||||
hi
|
||||
</strong>
|
||||
|
||||
<foo>
|
||||
sdkflsdfjk
|
||||
</foo>
|
||||
|
@ -110,31 +119,27 @@ hey
|
|||
=====================================output=====================================
|
||||
<p>
|
||||
Hi {{firstName}} {{lastName
|
||||
}}, welcome!
|
||||
}} , welcome!
|
||||
</p>
|
||||
{{#component propA}}
|
||||
for{{propB}}do{{propC}}f
|
||||
for {{propB}} do {{propC}} f
|
||||
{{/component}}
|
||||
{{#component propA}}
|
||||
for
|
||||
{{propB}}
|
||||
for {{propB}}
|
||||
<span>
|
||||
name
|
||||
</span>
|
||||
do
|
||||
{{propC}}
|
||||
f
|
||||
do {{propC}} f
|
||||
{{/component}}
|
||||
{{propA}}
|
||||
{{propB}}
|
||||
{{propC}}
|
||||
{{propD}}
|
||||
{{propA}} {{propB}}
|
||||
{{propC}}{{propD}}
|
||||
<span>
|
||||
{{propE}} {{propF}}
|
||||
</span>
|
||||
<span>
|
||||
{{propG}}{{propH}}
|
||||
</span>
|
||||
|
||||
hey
|
||||
================================================================================
|
||||
`;
|
||||
|
@ -294,22 +299,22 @@ conubia nostra, per inceptos himenaeos. Donec in ornare velit.</p>
|
|||
vestibulum facilisis in porta turpis. Ut faucibus lectus sit amet urna consectetur dignissim.
|
||||
Sam vitae neque quis ex dapibus faucibus at sed ligula. Nulla sit amet aliquet nibh.
|
||||
Vestibulum at congue mi. Suspendisse vitae odio vitae massa hendrerit mattis sed eget dui.
|
||||
Sed eu scelerisque neque. Donec<b
|
||||
>
|
||||
Sed eu scelerisque neque. Donec
|
||||
<b>
|
||||
maximus
|
||||
</b>
|
||||
rhoncus pellentesque. Aenean purus turpis, vehicula
|
||||
euismod ante vel, ultricies eleifend dui. Class aptent taciti sociosqu ad litora torquent per
|
||||
conubia nostra, per inceptos himenaeos. Donec in ornare velit.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce cursus massa vel augue
|
||||
vestibulum facilisis in porta turpis. Ut faucibus lectus sit amet urna consectetur dignissim.
|
||||
Sam vitae neque quis ex dapibus faucibus at sed ligula. Nulla sit amet aliquet nibh.
|
||||
Vestibulum at congue mi. Suspendisse vitae odio vitae massa hendrerit mattis sed eget dui.
|
||||
Sed eu scelerisque neque. Donec<a
|
||||
href="#"
|
||||
>
|
||||
Sed eu scelerisque neque. Donec
|
||||
<a href="#">
|
||||
<b>
|
||||
maximus
|
||||
</b>
|
||||
|
@ -365,10 +370,10 @@ printWidth: 40
|
|||
This is your name: {{name}}.
|
||||
</span>
|
||||
<span>
|
||||
This is your name: {{name}}(employee)
|
||||
This is your name: {{name}} (employee)
|
||||
</span>
|
||||
<span>
|
||||
This is your name: {{name}}({{role}})
|
||||
This is your name: {{name}} ({{role}})
|
||||
</span>
|
||||
================================================================================
|
||||
`;
|
||||
|
@ -410,6 +415,7 @@ printWidth: 40
|
|||
<span>
|
||||
123
|
||||
</span>
|
||||
|
||||
<div>
|
||||
123
|
||||
</div>
|
||||
|
@ -468,40 +474,44 @@ printWidth: 40
|
|||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
A
|
||||
</th>
|
||||
<th>
|
||||
B
|
||||
</th>
|
||||
<th>
|
||||
C
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
A
|
||||
</th>
|
||||
<th>
|
||||
B
|
||||
</th>
|
||||
<th>
|
||||
C
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
A
|
||||
</th>
|
||||
<th>
|
||||
B
|
||||
</th>
|
||||
<th>
|
||||
C
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
A
|
||||
</th>
|
||||
|
||||
<th>
|
||||
B
|
||||
</th>
|
||||
|
||||
<th>
|
||||
C
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
|
Loading…
Reference in New Issue