Skip to content
Merged
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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,16 @@ For instance, the following source would be rendered as `foo();` in Vaadin 23+,

Strictly, the constructor of `SourceCodeViewer` receives a map with arbitrary variables defined by the caller, and `TabbedDemo` defines "vaadin" and "flow" variables. Implementation details in PR https://github.com/FlowingCode/CommonsDemo/pull/44.

The `@DemoSource` annotation also supports a `condition` attribute to control the visibility of the source tab based on the environment. This feature uses the same syntax and operators as the conditional directives.


```java
@DemoSource(value = "/src/test/resources/META-INF/resources/frontend/example.css", condition = "vaadin ge 24")
public class MyDemo extends Div {
...
}
```

### Fragment highlighting

This feature supports highlighting a source code fragment in order to emphasize a section of the code snippet.
Expand Down
4 changes: 2 additions & 2 deletions 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.0.1-SNAPSHOT</version>
<version>5.1.0-SNAPSHOT</version>

<name>Commons Demo</name>
<description>Common classes for add-ons demo</description>
Expand Down Expand Up @@ -130,7 +130,7 @@
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.3.0</version>
<version>6.3.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Commons Demo
* %%
* Copyright (C) 2020 - 2025 Flowing Code
* Copyright (C) 2020 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -77,4 +77,6 @@
/** Source code position in the layout */
SourcePosition sourcePosition() default SourcePosition.SECONDARY;

String condition() default "";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*-
* #%L
* Commons Demo
* %%
* Copyright (C) 2020 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.flowingcode.vaadin.addons.demo;

import java.util.Map;
import lombok.NonNull;
import lombok.experimental.UtilityClass;

@UtilityClass
class DemoSourceConditionHelper {

public boolean eval(String condition, Map<String, String> env) {
if (condition == null) {
return true;
}

String[] expr = condition.split(" ");

if (expr.length == 3) {
String lhs = env.get(expr[0]);

if (lhs == null) {
return false;
}

String operator = expr[1];
String rhs = expr[2];

switch (operator) {
case "lt":
return compare(lhs, rhs) < 0;
case "le":
return compare(lhs, rhs) <= 0;
case "eq":
return compare(lhs, rhs) == 0;
case "ge":
return compare(lhs, rhs) >= 0;
case "gt":
return compare(lhs, rhs) > 0;
case "ne":
return compare(lhs, rhs) != 0;
default:
throw new IllegalArgumentException("Unknown operator: " + operator);
}
} else {
throw new IllegalArgumentException("Invalid condition: '" + condition
+ "'. Must be exactly 3 components: [VARIABLE] [OPERATOR] [VERSION]");
}
}

private int compare(String a, String b) {
String[] aa = split(a);
String[] bb = split(b);

int minLength = Math.min(aa.length, bb.length);

for (int i = 0; i < minLength; i++) {
int ai = Integer.parseInt(aa[i]);
int bi = Integer.parseInt(bb[i]);
int c = Integer.compare(ai, bi);
if (c != 0) {
return c;
}
}

return 0;
}

private String[] split(@NonNull String version) {
if (!version.matches("^\\d+(\\.\\d+){0,2}$")) {
throw new IllegalArgumentException("Invalid version: '" + version
+ "'. Must be 'major', 'major.minor', or major.minor.patch'");
}
return version.split("\\.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Commons Demo
* %%
* Copyright (C) 2020 - 2025 Flowing Code
* Copyright (C) 2020 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -25,6 +25,7 @@
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.tabs.Tab;
import elemental.json.JsonValue;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -42,6 +43,12 @@ public class MultiSourceCodeViewer extends Div {
private EnhancedTabs tabs;

public MultiSourceCodeViewer(List<SourceCodeTab> sourceCodeTabs, Map<String, String> properties) {
sourceCodeTabs = new ArrayList<>(sourceCodeTabs);
sourceCodeTabs.removeIf(tab -> !DemoSourceConditionHelper.eval(tab.getCondition(), properties));
if (sourceCodeTabs.isEmpty()) {
return;
}

if (sourceCodeTabs.size() > 1) {
tabs = new EnhancedTabs(createTabs(sourceCodeTabs));
tabs.addSelectedChangeListener(ev -> onTabSelected(ev.getSelectedTab()));
Expand Down Expand Up @@ -69,6 +76,10 @@ public MultiSourceCodeViewer(List<SourceCodeTab> sourceCodeTabs, Map<String, Str
getStyle().set("flex-direction", "column");
}

public boolean isEmpty() {
return selectedTab == null;
}

private Tab[] createTabs(List<SourceCodeTab> sourceCodeTabs) {
return sourceCodeTabs.stream().map(this::createTab).toArray(Tab[]::new);
}
Expand Down Expand Up @@ -134,7 +145,12 @@ private void fetchContents(String url, String language) {
}

public SourcePosition getSourcePosition() {
return (SourcePosition) ComponentUtil.getData(selectedTab, DATA_POSITION);
if (selectedTab != null) {
return (SourcePosition) ComponentUtil.getData(selectedTab, DATA_POSITION);
} else {
return SourcePosition.SECONDARY;
}

}

private Optional<Tab> findTabWithFilename(String filename) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Commons Demo
* %%
* Copyright (C) 2020 - 2024 Flowing Code
* Copyright (C) 2020 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -36,6 +36,7 @@ public class SourceCodeTab {
private final String url;
private String caption;
private String language;
private String condition;
@NonNull
private final SourcePosition sourcePosition;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Commons Demo
* %%
* Copyright (C) 2020 - 2023 Flowing Code
* Copyright (C) 2020 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -54,6 +54,10 @@ public SplitLayoutDemo(Component demo, List<SourceCodeTab> tabs) {
getContent().setSizeFull();
}

public boolean isEmpty() {
return code.isEmpty();
}

private void setSourcePosition(SourcePosition position) {
if (!position.equals(sourcePosition)) {
getContent().removeAll();
Expand Down
21 changes: 15 additions & 6 deletions src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Commons Demo
* %%
* Copyright (C) 2020 - 2025 Flowing Code
* Copyright (C) 2020 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -181,16 +181,21 @@ public void showRouterLayoutContent(HasElement content) {
}

if (!sourceTabs.isEmpty()) {
content = new SplitLayoutDemo(demo, sourceTabs);
currentLayout = (SplitLayoutDemo) content;
currentLayout = new SplitLayoutDemo(demo, sourceTabs);
if (currentLayout.isEmpty()) {
demo.getElement().removeAttribute("slot");
currentLayout = null;
}
}

if (currentLayout != null) {
content = currentLayout;
if (splitOrientation != null) {
setOrientation(splitOrientation);
updateSplitterPosition();
}

if (currentLayout != null) {
setupDemoHelperButton(currentLayout.getContent().getPrimaryComponent().getClass());
}
setupDemoHelperButton(currentLayout.getContent().getPrimaryComponent().getClass());
} else {
currentLayout = null;
demo.getElement().getStyle().set("height", "100%");
Expand Down Expand Up @@ -245,6 +250,10 @@ private Optional<SourceCodeTab> createSourceCodeTab(Class<?> annotatedClass, Dem
builder.language(annotation.caption());
}

if (!annotation.condition().isEmpty()) {
builder.condition(annotation.condition());
}

builder.sourcePosition(annotation.sourcePosition());

return Optional.of(builder.build());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*-
* #%L
* %%
* Copyright (C) 2020 - 2024 Flowing Code
* Copyright (C) 2020 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -29,9 +29,13 @@
// show-source @DemoSource
// show-source @DemoSource(clazz = AdditionalSources.class)
// show-source @DemoSource("/src/test/resources/META-INF/resources/frontend/multi-source-demo.css")
// show-source @DemoSource(value="/src/test/resources/META-INF/resources/frontend/condition-true.css", condition = "vaadin ge 14")
// show-source @DemoSource(value="/src/test/resources/META-INF/resources/frontend/condition-false.css", condition = "vaadin eq 0")
@DemoSource
@DemoSource(clazz = AdditionalSources.class)
@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")
public class MultiSourceDemo extends Div {
public MultiSourceDemo() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*-
* #%L
* Commons Demo
* %%
* Copyright (C) 2020 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.flowingcode.vaadin.addons.demo.it;

import com.flowingcode.vaadin.addons.GithubLink;
import com.flowingcode.vaadin.addons.demo.AdHocDemo;
import com.flowingcode.vaadin.addons.demo.DemoSource;
import com.flowingcode.vaadin.addons.demo.TabbedDemo;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.router.Route;

@SuppressWarnings("serial")
@GithubLink("https://github.com/FlowingCode/CommonsDemo")
public class TabbedDemoView extends TabbedDemo {

public TabbedDemoView() {
addDemo(TabbedDemoViewNoSource.class);
addDemo(TabbedDemoViewSingleSource.class);
addDemo(TabbedDemoViewMultiSource.class);
addDemo(TabbedDemoViewConditionalTrue.class);
addDemo(TabbedDemoViewConditionalFalse.class);
}

protected abstract static class AbstractDemoView extends Div {
public AbstractDemoView() {
add(new Span(this.getClass().getSimpleName()));
}
}

@Route(value = "it/tabbed-demo-no-source", layout = TabbedDemoView.class)
public static class TabbedDemoViewNoSource extends AbstractDemoView { }

@DemoSource(clazz = TabbedDemoView.class)
@Route(value = "it/tabbed-demo-single-source", layout = TabbedDemoView.class)
public static class TabbedDemoViewSingleSource extends AbstractDemoView { }

@DemoSource(clazz = TabbedDemoView.class)
@DemoSource(clazz = AdHocDemo.class)
@Route(value = "it/tabbed-demo-multi-source", layout = TabbedDemoView.class)
public static class TabbedDemoViewMultiSource extends AbstractDemoView { }

@DemoSource(clazz = TabbedDemoView.class, condition = "vaadin ge 14")
@Route(value = "it/tabbed-demo-conditional-true", layout = TabbedDemoView.class)
public static class TabbedDemoViewConditionalTrue extends AbstractDemoView { }

@DemoSource(clazz = TabbedDemoView.class, condition = "vaadin eq 0")
@Route(value = "it/tabbed-demo-conditional-false", layout = TabbedDemoView.class)
public static class TabbedDemoViewConditionalFalse extends AbstractDemoView { }
}
Loading