Skip to content

Commit 471f1da

Browse files
committed
Release 0.17.6 (#322)
Release 0.17.6
2 parents 8f93da4 + b2d6a79 commit 471f1da

File tree

10 files changed

+214
-43
lines changed

10 files changed

+214
-43
lines changed

OrchidCore/src/main/java/com/eden/orchid/api/resources/resource/FileResource.java

+24-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import com.eden.orchid.api.OrchidContext;
44
import com.eden.orchid.api.options.OrchidFlags;
55
import com.eden.orchid.api.theme.pages.OrchidReference;
6+
import kotlin.collections.ArraysKt;
7+
import kotlin.collections.CollectionsKt;
8+
import kotlin.text.StringsKt;
69
import org.apache.commons.io.IOUtils;
710

811
import java.io.File;
@@ -19,7 +22,7 @@
1922
* through the `page` variable. When used with renderRaw(), the raw contents (after having the embedded data removed)
2023
* will be written directly instead.
2124
*/
22-
public final class FileResource extends FreeableResource {
25+
public final class FileResource extends FreeableResource {
2326

2427
private final File file;
2528

@@ -38,13 +41,12 @@ public FileResource(File file, OrchidReference reference) {
3841

3942
@Override
4043
protected void loadContent() {
41-
if(rawContent == null) {
44+
if (rawContent == null) {
4245
try {
4346
if (file != null) {
4447
rawContent = IOUtils.toString(new FileInputStream(file), Charset.forName("UTF-8"));
4548
}
46-
}
47-
catch (IOException e) {
49+
} catch (IOException e) {
4850
e.printStackTrace();
4951
}
5052
}
@@ -58,22 +60,35 @@ private static String pathFromFile(OrchidContext context, File file) {
5860

5961
private static String pathFromFile(OrchidContext context, File file, String basePath) {
6062
String filePath = file.getPath();
63+
64+
// normalise Windows-style backslashes to common forward slashes
6165
basePath = basePath.replaceAll("\\\\", "/");
6266
filePath = filePath.replaceAll("\\\\", "/");
6367

64-
if(filePath.startsWith(basePath)) {
68+
// Remove the common base path from the actual file path
69+
if (filePath.startsWith(basePath)) {
6570
filePath = filePath.replaceAll(basePath, "");
6671
}
6772

73+
if (filePath.startsWith("/")) {
74+
filePath = StringsKt.removePrefix(filePath, "/");
75+
}
76+
77+
// if the path is not a child of the base path (i.e. still has relative path segments), strip those away. The
78+
// resolved "path" of this resource will be the portion after those relative segments.
79+
80+
filePath = CollectionsKt.joinToString(
81+
ArraysKt.filter(filePath.split("/"), (it) -> !(it.equals("..") || it.equals("."))),
82+
"/", "", "", -1, "", null);
83+
6884
return filePath;
6985
}
7086

7187
@Override
7288
public InputStream getContentStream() {
7389
try {
7490
return new FileInputStream(file);
75-
}
76-
catch (Exception e) {
91+
} catch (Exception e) {
7792
e.printStackTrace();
7893
return null;
7994
}
@@ -91,14 +106,14 @@ public boolean canDelete() {
91106

92107
@Override
93108
public void update(InputStream newContent) throws IOException {
94-
if(file != null && newContent != null) {
109+
if (file != null && newContent != null) {
95110
Files.write(file.toPath(), IOUtils.toByteArray(newContent));
96111
}
97112
}
98113

99114
@Override
100115
public void delete() throws IOException {
101-
if(file != null) {
116+
if (file != null) {
102117
file.delete();
103118
}
104119
}

OrchidCore/src/main/java/com/eden/orchid/api/theme/assets/AssetHolderDelegate.java

+13-28
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.eden.orchid.api.OrchidContext;
66
import com.eden.orchid.api.resources.resource.ExternalResource;
77
import com.eden.orchid.api.resources.resource.OrchidResource;
8-
import com.eden.orchid.api.theme.pages.OrchidPage;
98
import com.eden.orchid.utilities.OrchidUtils;
109
import org.apache.commons.io.FilenameUtils;
1110

@@ -91,7 +90,7 @@ public JsPage addJs(JsPage jsAsset) {
9190
}
9291

9392
private JsPage addJs(JsPage jsAsset, boolean renderImmediately) {
94-
return addAssetInternal(jsAsset, "js", renderImmediately);
93+
return addAssetInternal(jsAsset, renderImmediately);
9594
}
9695

9796
@Override
@@ -100,7 +99,7 @@ public CssPage addCss(CssPage cssAsset) {
10099
}
101100

102101
private CssPage addCss(CssPage cssAsset, boolean renderImmediately) {
103-
return addAssetInternal(cssAsset, "css", renderImmediately);
102+
return addAssetInternal(cssAsset, renderImmediately);
104103
}
105104

106105
@Override
@@ -109,52 +108,38 @@ public AssetPage addAsset(AssetPage asset) {
109108
}
110109

111110
private AssetPage addAsset(AssetPage asset, boolean renderImmediately) {
112-
return addAssetInternal(asset, null, renderImmediately);
111+
return addAssetInternal(asset, renderImmediately);
113112
}
114113

115114
// Add assets by string
116115
//----------------------------------------------------------------------------------------------------------------------
117116

118117
@Override
119118
public JsPage addJs(String jsAsset) {
120-
return addAssetInternal(jsAsset, "JS", true, JsPage::new, this::addJs);
119+
return addAssetInternal(jsAsset, true, JsPage::new, this::addJs);
121120
}
122121

123122
@Override
124123
public CssPage addCss(String cssAsset) {
125-
return addAssetInternal(cssAsset, "CSS", true, CssPage::new, this::addCss);
124+
return addAssetInternal(cssAsset, true, CssPage::new, this::addCss);
126125
}
127126

128127
@Override
129128
public AssetPage addAsset(String asset) {
130-
return addAssetInternal(asset, "", true, AssetPage::new, this::addAsset);
129+
return addAssetInternal(asset, true, AssetPage::new, this::addAsset);
131130
}
132131

133132
// internals
134133
//----------------------------------------------------------------------------------------------------------------------
135134

136-
private boolean validAsset(OrchidPage asset, String targetExtension) {
137-
return asset.getReference().getOutputExtension().equalsIgnoreCase(targetExtension);
135+
private <T extends AssetPage> T addAssetInternal(T asset, boolean renderImmediately) {
136+
asset.getReference().setUsePrettyUrl(false);
137+
AssetPage actualAsset = context.getAssetManager().addAsset(asset, renderImmediately);
138+
assets.add(actualAsset);
139+
return asset;
138140
}
139141

140-
private <T extends AssetPage> T addAssetInternal(T asset, String expectedOutputExtension, boolean renderImmediately) {
141-
if(expectedOutputExtension == null || validAsset(asset, expectedOutputExtension)) {
142-
asset.getReference().setUsePrettyUrl(false);
143-
AssetPage actualAsset = context.getAssetManager().addAsset(asset, renderImmediately);
144-
assets.add(actualAsset);
145-
return asset;
146-
}
147-
else {
148-
Clog.w("#{$1} is not a valid #{$2} asset, perhaps you are missing a #{$3}->#{$4} Compiler extension?",
149-
asset.getReference().getOriginalFullFileName(),
150-
expectedOutputExtension.toUpperCase(),
151-
asset.getReference().getOutputExtension(),
152-
expectedOutputExtension);
153-
return null;
154-
}
155-
}
156-
157-
private <T extends AssetPage> T addAssetInternal(String asset, String assetTypeName, boolean renderImmediately, CreateAssetInterface<T> creator, BiConsumer<T, Boolean> adder) {
142+
private <T extends AssetPage> T addAssetInternal(String asset, boolean renderImmediately, CreateAssetInterface<T> creator, BiConsumer<T, Boolean> adder) {
158143
OrchidResource resource = context.getResourceEntry(asset);
159144
if(resource != null) {
160145
boolean setPrefix = !EdenUtils.isEmpty(prefix);
@@ -174,7 +159,7 @@ private <T extends AssetPage> T addAssetInternal(String asset, String assetTypeN
174159
return page;
175160
}
176161
else {
177-
Clog.w("Could not find {} asset: {}", assetTypeName, asset);
162+
Clog.w("Could not find asset: {}", asset);
178163
}
179164

180165
return null;

OrchidCore/src/main/java/com/eden/orchid/api/theme/assets/AssetPage.java

+20
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
import com.eden.orchid.api.options.archetypes.AssetMetadataArchetype;
77
import com.eden.orchid.api.resources.resource.OrchidResource;
88
import com.eden.orchid.api.theme.pages.OrchidPage;
9+
import kotlin.collections.CollectionsKt;
10+
11+
import java.util.HashMap;
12+
import java.util.Map;
913

1014
@Archetype(value = AssetMetadataArchetype.class, key = "assetmeta")
1115
@Description(value = "A static asset, like Javascript, CSS, or an image.", name = "Asset")
@@ -19,6 +23,10 @@ public class AssetPage extends OrchidPage {
1923
@Description("The asset alt text.")
2024
private String alt;
2125

26+
@Option
27+
@Description("Arbitrary attributes to apply to this element when rendered to page")
28+
private Map<String, String> attrs = new HashMap<>();
29+
2230
public AssetPage(Object source, String sourceKey, OrchidResource resource, String key, String title) {
2331
super(resource, key, title);
2432
this.source = source;
@@ -30,6 +38,10 @@ public String renderAssetToPage() {
3038
return "";
3139
}
3240

41+
protected String renderAttrs() {
42+
return CollectionsKt.joinToString(attrs.entrySet(), " ", "", "", -1, "...", entry -> "" + entry.getKey() + "=\"" + entry.getValue() + "\"");
43+
}
44+
3345
@Override
3446
public String getLink() {
3547
if(!rendered) {
@@ -76,4 +88,12 @@ public void setRendered(boolean rendered) {
7688
public void setAlt(String alt) {
7789
this.alt = alt;
7890
}
91+
92+
public Map<String, String> getAttrs() {
93+
return attrs;
94+
}
95+
96+
public void setAttrs(Map<String, String> attrs) {
97+
this.attrs = attrs;
98+
}
7999
}

OrchidCore/src/main/java/com/eden/orchid/api/theme/assets/CssPage.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ public CssPage(Object source, String sourceKey, OrchidResource resource, String
1313

1414
public String renderAssetToPage() {
1515
if (resource instanceof InlineResource) {
16-
return "<style>\n" + resource.compileContent(this) + "\n</style>";
16+
return "<style " + renderAttrs() + ">\n" + resource.compileContent(this) + "\n</style>";
1717
}
1818
else {
19-
return "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + this.getLink() + "\"/>";
19+
return "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + this.getLink() + "\" " + renderAttrs() + "/>";
2020
}
2121
}
2222

OrchidCore/src/main/java/com/eden/orchid/api/theme/assets/JsPage.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ public JsPage(Object source, String sourceKey, OrchidResource resource, String k
1919

2020
public String renderAssetToPage() {
2121
if (resource instanceof InlineResource) {
22-
return "<script>\n" + resource.compileContent(this) + "\n</script>";
22+
return "<script " + renderAttrs() + ">\n" + resource.compileContent(this) + "\n</script>";
2323
} else {
24-
String tagString = "<script";
24+
String tagString = "<script " + renderAttrs();
2525
if (async) {
2626
tagString += " async";
2727
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
- Removes restrictions on filenames that can be used for assets. CSS assets no longer requires a `.css` extension, and
2+
likewise JavaScript assets no longer require a `.js` extension. It's up to you to make sure an asset is valid or not
3+
before it gets added to the page.
4+
- When creating a Reference to a file that is not a child of the base dir, remove relative path segments so that it will
5+
be copied properly to the rendered site, and not outside of the build dir.
6+
- Adds `kotlinPlayground` component to the `OrchidSyntaxHighlighter` artifact, for converting Kotlin code snippets into
7+
runnable playgrounds.

OrchidCore/src/orchid/resources/pages/plugins/OrchidSyntaxHighlighter/index.md

+27-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ tags:
1212
## About
1313

1414
Add syntax highlighting to code snippets in your Orchid site. Supports pre-rendered highlighting with
15-
[Pygments](http://pygments.org/), and browser-based highlighting with [PrismJS](https://prismjs.com/)
15+
[Pygments](http://pygments.org/), browser-based highlighting with [PrismJS](https://prismjs.com/), and runnable Kotlin
16+
code snippets with [Kotlin Playground](https://github.com/JetBrains/kotlin-playground).
1617

1718
## Demo
1819

@@ -96,3 +97,28 @@ allPages:
9697
- 'kotlin'
9798
- 'yaml'
9899
```
100+
101+
### Kotlin Playground
102+
103+
The Kotlin Playground allows you to convert Kotlin code snippets into playgrounds that are runnable right in your
104+
browser. The `kotlinPlayground` component adds the script from their CDN, which will select all elements on the page
105+
with your runnable Kotlin code and convert them into embedded runnable playgrounds. By default, all Markdown code
106+
snippets with a language of `run-kotlin` are converted.
107+
108+
```yaml
109+
allPages:
110+
components:
111+
- type: 'pageContent'
112+
- type: 'kotlinPlayground'
113+
selector: "pre code[class='language-run-kotlin']"
114+
```
115+
116+
You can configure each individual playground using the attributes described in the [Kotlin playground docs](https://github.com/JetBrains/kotlin-playground#customizing-editors).
117+
These can be added from Markdown snippets with the following syntax:
118+
119+
```run-kotlin
120+
fun main() {
121+
println("Running from Kotlin Playground!")
122+
}
123+
```
124+
{theme='idea' lines='true'}

languageExtensions/OrchidSyntaxHighlighter/src/main/kotlin/com/eden/orchid/languages/highlighter/SyntaxHighlighterModule.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.eden.orchid.languages.highlighter
33
import com.eden.orchid.api.compilers.TemplateTag
44
import com.eden.orchid.api.registration.OrchidModule
55
import com.eden.orchid.api.theme.components.OrchidComponent
6+
import com.eden.orchid.languages.highlighter.components.KotlinPlaygroundComponent
67
import com.eden.orchid.languages.highlighter.components.PrismComponent
78
import com.eden.orchid.languages.highlighter.tags.HighlightTag
89
import com.eden.orchid.utilities.addToSet
@@ -13,6 +14,9 @@ class SyntaxHighlighterModule : OrchidModule() {
1314
withResources(750)
1415

1516
addToSet<TemplateTag, HighlightTag>()
16-
addToSet<OrchidComponent, PrismComponent>()
17+
addToSet<OrchidComponent>(
18+
PrismComponent::class,
19+
KotlinPlaygroundComponent::class
20+
)
1721
}
1822
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.eden.orchid.languages.highlighter.components
2+
3+
import com.eden.orchid.api.OrchidContext
4+
import com.eden.orchid.api.options.annotations.Description
5+
import com.eden.orchid.api.options.annotations.Option
6+
import com.eden.orchid.api.options.annotations.StringDefault
7+
import com.eden.orchid.api.theme.components.OrchidComponent
8+
import javax.inject.Inject
9+
10+
@Description(
11+
"Add the Kotlin Playground to your pages, to convert Kotlin code snippets into interactive, embedded " +
12+
"development playgrounds.",
13+
name = "Kotlin Playground"
14+
)
15+
class KotlinPlaygroundComponent
16+
@Inject
17+
constructor(
18+
context: OrchidContext
19+
) : OrchidComponent(context, "kotlinPlayground", 100) {
20+
21+
@Option
22+
@Description("The base URL to load Kotlin Playground JS files from.")
23+
@StringDefault("https://unpkg.com/kotlin-playground@1")
24+
lateinit var kotlinPlaygroundSource: String
25+
26+
@Option
27+
@Description("Select which elements on the page are converted. Defaults to markdown code blocks with the " +
28+
"`run-kotlin` language."
29+
)
30+
@StringDefault("pre code[class='language-run-kotlin']")
31+
lateinit var selector: String
32+
33+
@Option
34+
@Description("The URL to a self-hosted server instance for running code snippets.")
35+
lateinit var server: String
36+
37+
override fun loadAssets() {
38+
addJs(kotlinPlaygroundSource).apply {
39+
attrs["data-selector"] = selector
40+
41+
if (server.isNotBlank()) {
42+
attrs["data-server"] = server
43+
}
44+
}
45+
}
46+
47+
override fun isHidden(): Boolean {
48+
return true
49+
}
50+
}

0 commit comments

Comments
 (0)