Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Store all text files with LF in the repository, and check them out with LF
# on every platform. The source code viewer compares lines verbatim against
# the expected output of the integration tests, which fails on a CRLF checkout.
* text=auto eol=lf
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Commonly used boilerplate code from source snippets is automatically hidden:
- `@org.junit.Ignore`
- Calls to `SourceCodeViewer.highlight`, `SourceCodeViewer.highlightOnHover` and `SourceCodeViewer.highlightOnClick`

This feature cannot be disabled.
This feature cannot be disabled, but a line ending with a `// show-source` comment is always rendered. The comment itself is removed, so the line is rendered as it is written.

<!-- FROM https://github.com/FlowingCode/CommonsDemo/pull/37 -->
![image](https://github.com/FlowingCode/CommonsDemo/assets/11554739/083cf7ec-0f36-4db8-ab61-6c24650f4f13)
Expand Down Expand Up @@ -230,8 +230,8 @@ The highlighted fragment is automatically scrolled into view.

A fragment is highlighted either by calling `SourceCodeViewer.highlight(filenameAndId)` or when clicking/hovering a component that has been configured with `SourceCodeViewer.highlightOnClick` or `SourceCodeViewer.highlightOnHover`, where `filenameAndId` is the name of the fragment. If the component is in an additional source file, `filenameAndId` can be given as a string in the format `filename#id`. If no `'#'` is present, it is assumed that the identifier corresponds to a block in the first source panel. `SourceCodeViewer.highlight(null)` turns off the highlighting.

In the source code, a fragment is delimited by `// begin-block filenameAndId` and `// end-block` comments. Nested fragments are not supported.
The `// begin-block` and `// end-block` comments are removed after post-processing.
In the source code, a fragment is delimited by `// begin-block id` and `// end-block` comments. Nested fragments are not supported.
The begin-block and end-block comments are removed after post-processing.

```
// begin-block first
Expand All @@ -245,6 +245,16 @@ The `// begin-block` and `// end-block` comments are removed after post-processi
add(other);
```

The delimiters can also be written as block comments, which is the only option in languages that have no line comments, such as CSS.

```css
/* begin-block dashed */
.dashed {
border: 1px dashed black;
}
/* end-block */
```

<!-- FROM https://github.com/FlowingCode/CommonsDemo/pull/62 -->
![image](https://github.com/FlowingCode/CommonsDemo/assets/11554739/02063272-029f-4b4b-bd6f-821f2f8a0158)

Expand Down
2 changes: 1 addition & 1 deletion base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.flowingcode.vaadin.addons.demo</groupId>
<artifactId>commons-demo</artifactId>
<version>5.4.1-SNAPSHOT</version>
<version>5.5.0-SNAPSHOT</version>

<name>Commons Demo</name>
<description>Common classes for add-ons demo</description>
Expand Down
58 changes: 45 additions & 13 deletions base/src/main/resources/META-INF/resources/frontend/code-viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,9 @@
return lines.filter(line=>line!==null)
.map(line=>line!)
.filter(line=>
!line.match("//\\s*hide-source(\\s|$)")
//a trailing show-source comment overrides the boilerplate removal
line.match(/\/\/\s*show-source\s*$/)!=null

Check warning on line 342 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBT11Ew46Ft2gWGUI5&open=AaCBT11Ew46Ft2gWGUI5&pullRequest=167
|| (!line.match("//\\s*hide-source(\\s|$)")

Check warning on line 343 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBT11Ew46Ft2gWGUI6&open=AaCBT11Ew46Ft2gWGUI6&pullRequest=167

Check warning on line 343 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

`String.raw` should be used to avoid escaping `\`.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBT11Ew46Ft2gWGUI7&open=AaCBT11Ew46Ft2gWGUI7&pullRequest=167
&& !line.startsWith('@Route')
&& !line.startsWith('@PageTitle')
&& !line.startsWith('@SuppressWarnings')
Expand All @@ -350,10 +352,13 @@
&& line != 'import com.vaadin.flow.router.PageTitle;'
&& line != 'import com.vaadin.flow.router.Route;'
&& line != 'import com.flowingcode.vaadin.addons.demo.DemoSource;'
&& line != 'import org.junit.Ignore;'
&& line != 'import org.junit.Ignore;')
).map(line=>{
let m= line!.match("^(?<spaces>\\s*)//\\s*show-source\\s(?<line>.*)");
return m?m.groups!.spaces+m.groups!.line : line;
if (m) return m.groups!.spaces+m.groups!.line;
//remove a trailing show-source comment
const suffix = /\/\/\s*show-source\s*$/.exec(line!);
return suffix ? line!.slice(0,suffix.index).trimEnd() : line!;
})
.join('\n');
}
Expand Down Expand Up @@ -415,30 +420,57 @@
//remove trailing \n and spaces from text node i
const node = nodes[i]
if (node && node.nodeType==3) {
node.textContent=(node.textContent as any).replaceAll(/\n[\t\x20]+$/g,'');
node.textContent=(node.textContent as any).replaceAll(/\n[\t\x20]*$/g,'');
}
}


const trimStart = (i:number) => {
//remove the leading \n from text node i
const node = nodes[i]
if (node && node.nodeType==3) {

Check warning on line 430 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBpnq4k147qZEuEAXZ&open=AaCBpnq4k147qZEuEAXZ&pullRequest=167
node.textContent=(node.textContent as any).replace(/^\n/,'');
}
}

//remove the line of the delimiter at node i. When the delimiter is the first
//node there is no preceding text node, so the following one is trimmed instead.
const trimDelimiter = (i:number) => {
if (i>0) {
trimEnd(i-1);
} else {
trimStart(i+1);
}
}

//return the body of a line (//...) or block (/*...*/) comment, or undefined if the
//text is not a comment. Block comments are used by languages that lack line comments.
const commentBody = (text:string) : string|undefined => {
const m = text.match("^//(.*)") ?? text.match("^/\\*((?:[^*]|\\*(?!/))*)\\*/");

Check warning on line 448 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBe5UqmzjmZwMmA7UM&open=AaCBe5UqmzjmZwMmA7UM&pullRequest=167

Check warning on line 448 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBe5UqmzjmZwMmA7UN&open=AaCBe5UqmzjmZwMmA7UN&pullRequest=167

Check warning on line 448 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

`String.raw` should be used to avoid escaping `\`.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBe5UqmzjmZwMmA7UO&open=AaCBe5UqmzjmZwMmA7UO&pullRequest=167
return m ? m[1] : undefined;
}

var last : string|undefined;
for (var i=0; i<nodes.length; i++) {
//process instructions in element nodes
if (nodes[i].nodeType!=1) continue;

const text = nodes[i].textContent!;
var m = text.match("^//\\s*begin-block\\s+(\\S+)\\s*");


const text = commentBody(nodes[i].textContent!);
if (text===undefined) continue;
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const m = text.match("^\\s*begin-block\\s+(\\S+)\\s*");

Check warning on line 460 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBe5UqmzjmZwMmA7UP&open=AaCBe5UqmzjmZwMmA7UP&pullRequest=167

Check warning on line 460 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

`String.raw` should be used to avoid escaping `\`.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBe5UqmzjmZwMmA7UQ&open=AaCBe5UqmzjmZwMmA7UQ&pullRequest=167

if (m) {
last = m[1];
(nodes[i] as HTMLElement).classList.add('begin-'+m[1]);
nodes[i].textContent='';
trimEnd(i-1);
trimDelimiter(i);
continue;
}
if (text.match("^//\\s*end-block\\s*") && last) {

if (text.match("^\\s*end-block\\s*") && last) {

Check warning on line 470 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the "RegExp.exec()" method instead.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBT11Ew46Ft2gWGUJF&open=AaCBT11Ew46Ft2gWGUJF&pullRequest=167

Check warning on line 470 in base/src/main/resources/META-INF/resources/frontend/code-viewer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

`String.raw` should be used to avoid escaping `\`.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_CommonsDemo&issues=AaCBT11Ew46Ft2gWGUJG&open=AaCBT11Ew46Ft2gWGUJG&pullRequest=167
(nodes[i] as HTMLElement).classList.add('end-'+last);
nodes[i].textContent='';
trimEnd(i-1);
trimDelimiter(i);
continue;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
@DemoSource("/src/test/resources/META-INF/resources/frontend/multi-source-demo.css")
@DemoSource(value="/src/test/resources/META-INF/resources/frontend/condition-true.css", condition = "vaadin ge 14")
@DemoSource(value="/src/test/resources/META-INF/resources/frontend/condition-false.css", condition = "vaadin eq 0")
@StyleSheet("./multi-source-demo.css")
@StyleSheet("context://frontend/multi-source-demo.css")
public class MultiSourceDemo extends Div {
public MultiSourceDemo() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,42 @@
@Route(value = "demo/highlight", layout = Demo.class)
@PageTitle("Highlight")
@DemoSource
@StyleSheet("./highlight-demo.css")
@DemoSource("/src/test/resources/META-INF/resources/frontend/highlight-demo.css")
@StyleSheet("context://frontend/highlight-demo.css")
public class SampleDemoHighlight extends Div {

public SampleDemoHighlight() {
add(new Span("Highlight source fragments"));

// begin-block first
Div first = new Div(new Text("First"));
SourceCodeViewer.highlightOnHover(first, "first");
first.addClassName("dashed"); // hide-source
Div first = new Div(new Text("Highlight on hover (first)"));
SourceCodeViewer.highlightOnHover(first, "first"); // show-source
first.addClassName("dashed");
add(first);
// end-block

// begin-block second
Div second = new Div(new Text("Second"));
SourceCodeViewer.highlightOnHover(second, "second");
second.addClassName("dashed"); // hide-source
Div second = new Div(new Text("Highlight on hover (second)"));
SourceCodeViewer.highlightOnHover(second, "second"); // show-source
second.addClassName("dashed");
add(second);
// end-block

Div third = new Div(new Text("Highlight on hover (CSS)"));
SourceCodeViewer.highlightOnHover(third, "highlight-demo.css#dashed"); // show-source
third.addClassName("dashed");
add(third);

HorizontalLayout hl = new HorizontalLayout();

// begin-block button
Button button = new Button("Click me");
SourceCodeViewer.highlightOnClick(button, "button");
Button button = new Button("Highlight on click");
SourceCodeViewer.highlightOnClick(button, "button"); // show-source
add(button);
// end-block

hl.add(new Button("Highlight Off", ev -> {
SourceCodeViewer.highlight(null);
SourceCodeViewer.highlight(null); // show-source
}));

add(hl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,23 @@ private String getResourceName() {
}

protected String open(String... args) {
String resource = getResourceName();
return openSource(getResourceName(), "java", args);
}

/** Opens the stylesheet resource named after the test method. */
protected String openCss(String... args) {
return openSource(getResourceName(), "css", args);
}

private String openSource(String resource, String extension, String... args) {
if (viewer != null) {
throw new IllegalStateException();
}

String path = "com/flowingcode/vaadin/addons/demo/it/" + resource;
String params = Stream.of(args).map(Object::toString).collect(Collectors.joining(";"));
getDriver().get(getURL(String.format("it/view/%s?src/test/resources/%s.java", params, path)));
getDriver()
.get(getURL(String.format("it/view/%s?src/test/resources/%s.%s", params, path, extension)));
viewer = $(SourceCodeViewerElement.class).waitForFirst();
return viewer.getText();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,27 @@

import com.vaadin.testbench.TestBenchElement;
import com.vaadin.testbench.elementsbase.Element;
import org.openqa.selenium.By;

@Element("code-viewer")
public class SourceCodeViewerElement extends TestBenchElement {


private static final String LANGUAGE_PREFIX = "language-";

/**
* Returns the language that was used for formatting the source, as identified by the
* {@code language-} class of the rendered code, or {@code null} if there is none.
*/
public String getLanguage() {
String className = findElement(By.tagName("code")).getAttribute("class");
if (className != null) {
for (String s : className.split("\\s+")) {
if (s.startsWith(LANGUAGE_PREFIX)) {
return s.substring(LANGUAGE_PREFIX.length());
}
}
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public void testShowSource() {
assertEquals(expected(), open());
}

@Test
public void testShowSourceOverride() {
assertEquals(expected(), open());
}

@Test
public void testPackageCleanup() {
assertEquals(expected(), open());
Expand All @@ -59,4 +64,10 @@ public void testCleanupOverride() {
assertEquals(expected(), open());
}

@Test
public void testCssFragment() {
assertEquals(expected(), openCss());
Comment thread
javier-godoy marked this conversation as resolved.
assertEquals("css", viewer.getLanguage());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public void setParameter(BeforeEvent event, @OptionalParameter String parameter)
}

String url = event.getLocation().getQueryParameters().getQueryString();
add(new SourceCodeViewer(url, properties));
String language = url.endsWith(".css") ? "css" : "java";
add(new SourceCodeViewer(url, language, properties));
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/* begin-block dashed */
.dashed {
border: 1px dashed black;
padding: 1ex;
margin: 1ex;
}
/* end-block */

.dashed:hover {
background: var(--lumo-contrast-10pct);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* begin-block fragment */
.foo {
color: red;
}
/* end-block */

.bar {
color: blue;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.foo {
color: red;
}

.bar {
color: blue;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class MyClass {

SourceCodeViewer.highlight(null); // show-source
SourceCodeViewer.highlightOnHover(div, "first"); // show-source
SourceCodeViewer.highlightOnClick(div, "second");

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class MyClass {

SourceCodeViewer.highlight(null);
SourceCodeViewer.highlightOnHover(div, "first");

}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>com.flowingcode.vaadin.addons.demo</groupId>
<artifactId>commons-demo-aggregator</artifactId>
<version>5.4.1-SNAPSHOT</version>
<version>5.5.0-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Commons Demo Aggregator</name>
Expand Down
2 changes: 1 addition & 1 deletion processor/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.flowingcode.vaadin.addons.demo</groupId>
<artifactId>commons-demo-processor</artifactId>
<version>5.4.1-SNAPSHOT</version>
<version>5.5.0-SNAPSHOT</version>

<name>Commons Demo Processor</name>
<description>Annotation processor for Commons Demo: copies @DemoSource-referenced files into the class output</description>
Expand Down
Loading