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
12 changes: 9 additions & 3 deletions scripts/cn1playground/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,19 @@ Additional imports can be declared in scripts as needed.

### Shareable Links

The playground can generate shareable URLs that contain the script source code. Use the **"Copy Shareable Playground URL"** option in the side menu to copy a link to the clipboard.
The playground can generate shareable URLs that contain both the Java script source and CSS editor content. Use the **"Copy Shareable Playground URL"** option in the side menu to copy a link to the clipboard.

**URL Format**:
- Java source is stored in the `code` query parameter.
- CSS source is stored in the `css` query parameter.
- Both values use URL-safe Base64 encoding.

**URL Format**: The generated URL uses a `code` query parameter with URL-safe Base64-encoded script content:
```
https://example.com/playground?code=<base64-encoded-script>
https://example.com/playground?code=<base64-encoded-script>&css=<base64-encoded-css>
```

If the CSS editor is empty, the `css` parameter is omitted.

The encoding uses URL-safe Base64 (replacing `+` with `-` and `/` with `_`, with padding removed).

**Sample Links**: You can also link to built-in samples using the `sample` query parameter:
Expand Down
1 change: 1 addition & 0 deletions scripts/cn1playground/common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>


<!-- Add your cn1lib dependencies to this section -->
<dependencies>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import bsh.cn1.CN1AccessRegistry;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Map;
Expand Down Expand Up @@ -118,7 +117,7 @@ public void addClassPath(Object path) {}
protected String getClassNameByUnqName(String name) throws UtilEvalError { throw cmUnavailable(); }
public void addListener(Listener l) {}
public void removeListener(Listener l) {}
public void dump(PrintWriter pw) { pw.println("BshClassManager: reduced CN1 runtime."); }
public void dump() {}
public Class<?> defineClass(String name, byte[] code) { throw new InterpreterError("Class generation is disabled."); }
protected void classLoaderChanged() {}

Expand Down
14 changes: 10 additions & 4 deletions scripts/cn1playground/common/src/main/java/bsh/BshMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
package bsh;

import java.io.Serializable;
import java.util.Arrays;

/**
This represents an instance of a bsh method declaration in a particular
Expand Down Expand Up @@ -592,8 +591,15 @@ private void reloadTypes() {
/** {@inheritDoc} */
@Override
public void classLoaderChanged() {
reload = Reflect.isGeneratedClass(creturnType)
|| Arrays.asList(cparamTypes).stream()
.anyMatch(Reflect::isGeneratedClass);
reload = Reflect.isGeneratedClass(creturnType);
if (reload || cparamTypes == null) {
return;
}
for (Class<?> paramType : cparamTypes) {
if (Reflect.isGeneratedClass(paramType)) {
reload = true;
return;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package bsh;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;

/** Reduced UTF-8 reader wrapper for CN1 runtime use. */
final public class FileReader extends InputStreamReader {
public FileReader(String path) throws FileNotFoundException {
public FileReader(String path) {
this(openUnsupported(path));
}

public FileReader(InputStream in) {
super(in);
}

private static InputStream openUnsupported(String path) throws FileNotFoundException {
throw new FileNotFoundException("File access is disabled in the reduced CN1 runtime: " + path);
private static InputStream openUnsupported(String path) {
throw new UnsupportedOperationException("File access is disabled in the reduced CN1 runtime: " + path);
}
}
15 changes: 0 additions & 15 deletions scripts/cn1playground/common/src/main/java/bsh/Interpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
package bsh;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.Serializable;
Expand Down Expand Up @@ -1115,20 +1114,6 @@ public Interpreter getParent() {
return parent;
}

/**
De-serialization setup.
Default out and err streams to stdout, stderr if they are null.
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
stream.defaultReadObject();

// set transient fields
setOut( System.out );
setErr( System.err );
}

/**
Get the prompt string defined by the getBshPrompt() method in the
global namespace. This may be from the getBshPrompt() command or may
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ public JavaCharStream(final java.io.InputStream dstream,
final int startcolumn,
final int buffersize)
{
this(new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}

/** Constructor. */
Expand Down Expand Up @@ -340,7 +340,7 @@ public void reInit(final java.io.InputStream dstream,
final int startcolumn,
final int buffersize)
{
reInit(new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
reInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}

@Override
Expand Down
28 changes: 0 additions & 28 deletions scripts/cn1playground/common/src/main/java/bsh/LHS.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@
*****************************************************************************/
package bsh;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Map.Entry;
import java.util.Objects;
Expand Down Expand Up @@ -327,29 +324,4 @@ public String toString() {
+(nameSpace!=null ? " nameSpace = "+nameSpace.toString(): "");
}

/** Reflect Field is not serializable, hide it.
* @param s serializer
* @throws IOException mandatory throwing exception */
private synchronized void writeObject(final ObjectOutputStream s) throws IOException {
if ( null != field ) {
this.object = field.getDeclaringClass();
this.varName = field.getName();
this.field = null;
}
s.defaultWriteObject();
}

/** Fetch field removed from serializer.
* @param in secializer.
* @throws IOException mandatory throwing exception
* @throws ClassNotFoundException mandatory throwing exception */
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
if ( null == this.object )
return;
Class<?> cls = this.object.getClass();
if ( this.object instanceof Class )
cls = (Class<?>) this.object;
this.field = BshClassManager.memberCache.get(cls).findField(varName);
}
}
22 changes: 0 additions & 22 deletions scripts/cn1playground/common/src/main/java/bsh/NameSpace.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@
*****************************************************************************/
package bsh;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -1135,25 +1132,6 @@ public String toString() {
+ (this.classInstance != null ? " (class instance) " : "");
}

/** Write object.
* @param s the s
* @throws IOException Signals that an I/O exception has occurred. For
* serialization. Don't serialize non-serializable objects. */
private synchronized void writeObject(final ObjectOutputStream s)
throws IOException {
// clear name resolvers... don't know if this is necessary.
this.names.clear();
s.defaultWriteObject();
}
/** Re-initialize transient members.
* @param in the serializer
* @throws IOException mandatory throwing exception
* @throws ClassNotFoundException mandatory throwing exception */
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();

this.classCache = new HashMap<>();
}
/** Invoke a method in this namespace with the specified args and
* interpreter reference. No caller information or call stack is required.
* The method will appear as if called externally from Java.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ private static String argsTypesString(Object[] args) {
List<String> typesString = new ArrayList<String>();
for (Class<?> typeClass: Types.getTypes(args))
typesString.add(typeClass != null ? Types.prettyName(typeClass) : "null");
return String.join(", ", typesString);
StringBuilder out = new StringBuilder();
for (int i = 0; i < typesString.size(); i++) {
if (i > 0) {
out.append(", ");
}
out.append(typesString.get(i));
}
return out.toString();
}

/** Create a error for when can't construct a instance */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void runApp() {
CN.setProperty("platformHint.javascript.beforeUnloadMessage", null);
theme = Resources.getGlobalResources();
currentScript = resolveInitialScript();
currentCss = PlaygroundStateStore.loadCurrentCss();
currentCss = resolveInitialCss();

appForm = new Form("Playground", new BorderLayout());
appForm.setUIID("PlaygroundForm");
Expand Down Expand Up @@ -307,12 +307,17 @@ private Button createSideMenuButton(String text, Runnable action) {
private String resolveInitialScript() {
String sharedScript = scriptFromUrl();
if (sharedScript != null) {
PlaygroundStateStore.saveCurrentState(sharedScript, PlaygroundStateStore.loadCurrentCss(), PlaygroundStateStore.loadCurrentOutput());
PlaygroundStateStore.saveCurrentState(sharedScript, resolveInitialCss(), PlaygroundStateStore.loadCurrentOutput());
return sharedScript;
}
return PlaygroundStateStore.loadCurrentScript();
}

private String resolveInitialCss() {
String sharedCss = cssFromUrl();
return sharedCss == null ? PlaygroundStateStore.loadCurrentCss() : sharedCss;
}

private String scriptFromUrl() {
String href = CN.getProperty("browser.window.location.href", null);
if (href == null || href.isEmpty()) {
Expand All @@ -332,6 +337,22 @@ private String scriptFromUrl() {
return found == null ? null : found.script;
}

private String cssFromUrl() {
String href = CN.getProperty("browser.window.location.href", null);
if (href == null || href.isEmpty()) {
return null;
}

String css = queryParam(href, "css");
if (css != null && !css.isEmpty()) {
String decoded = decodeSharedScript(css);
if (decoded != null && !decoded.trim().isEmpty()) {
return decoded;
}
}
return null;
}

private String queryParam(String href, String name) {
int queryStart = href.indexOf('?');
if (queryStart < 0 || queryStart == href.length() - 1) {
Expand Down Expand Up @@ -388,7 +409,13 @@ private void copyCurrentSourceUrl() {
return;
}

Display.getInstance().copyToClipboard(base + "?code=" + encoded);
StringBuilder shareUrl = new StringBuilder(base).append("?code=").append(encoded);
if (currentCss != null && !currentCss.isEmpty()) {
String encodedCss = encodeSharedScript(currentCss);
shareUrl.append("&css=").append(encodedCss);
}

Display.getInstance().copyToClipboard(shareUrl.toString());
}

private String encodeSharedScript(String script) {
Expand Down
Loading