mirror of
https://github.com/processing/processing4.git
synced 2026-02-14 10:55:38 +01:00
javascript mode: added server as runner, custom templates, directives support, latest pjs v1.2.1
This commit is contained in:
538
app/src/processing/mode/javascript/DirectivesEditor.java
Normal file
538
app/src/processing/mode/javascript/DirectivesEditor.java
Normal file
@@ -0,0 +1,538 @@
|
||||
package processing.mode.javascript;
|
||||
|
||||
import processing.mode.java.JavaEditor;
|
||||
import processing.app.Base;
|
||||
import processing.app.Sketch;
|
||||
import processing.app.SketchCode;
|
||||
|
||||
import processing.core.PApplet;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.border.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Vector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
/* http://processingjs.org/reference/pjs%20directive */
|
||||
|
||||
public class DirectivesEditor
|
||||
{
|
||||
JavaScriptEditor editor;
|
||||
|
||||
static JFrame frame;
|
||||
JCheckBox crispBox;
|
||||
JTextField fontField;
|
||||
JCheckBox globalKeyEventsBox;
|
||||
JCheckBox pauseOnBlurBox;
|
||||
JTextField preloadField;
|
||||
JCheckBox transparentBox;
|
||||
|
||||
private final static ArrayList<String> validKeys = new ArrayList<String>();
|
||||
static {
|
||||
validKeys.add("crisp");
|
||||
validKeys.add("font");
|
||||
validKeys.add("globalKeyEvents");
|
||||
validKeys.add("pauseOnBlur");
|
||||
validKeys.add("preload");
|
||||
validKeys.add("transparent");
|
||||
}
|
||||
private final static int CRISP = 0;
|
||||
private final static int FONT = 1;
|
||||
private final static int GLOBAL_KEY_EVENTS = 2;
|
||||
private final static int PAUSE_ON_BLUR = 3;
|
||||
private final static int PRELOAD = 4;
|
||||
private final static int TRANSPARENT = 5;
|
||||
|
||||
private Pattern pjsPattern;
|
||||
|
||||
public DirectivesEditor ( JavaScriptEditor e )
|
||||
{
|
||||
editor = e;
|
||||
|
||||
if ( frame == null ) createFrame();
|
||||
|
||||
// see processing-1.2.0.js
|
||||
pjsPattern = Pattern.compile(
|
||||
"\\/\\*\\s*@pjs\\s+((?:[^\\*]|\\*+[^\\*\\/])*)\\*\\/\\s*",
|
||||
Pattern.DOTALL );
|
||||
}
|
||||
|
||||
public void show ()
|
||||
{
|
||||
if ( editor.getSketch().isModified())
|
||||
{
|
||||
Base.showWarning( "Directives Editor", "Please save your sketch before changing the directives.", null);
|
||||
//editor.statusError("Please save your sketch before changing the directives.");
|
||||
return;
|
||||
}
|
||||
|
||||
resetInterface();
|
||||
findRemoveDirectives(false);
|
||||
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
private void resetInterface ()
|
||||
{
|
||||
for ( JCheckBox b : new JCheckBox[]{ crispBox, globalKeyEventsBox, pauseOnBlurBox, transparentBox } )
|
||||
{
|
||||
b.setSelected(false);
|
||||
}
|
||||
for ( JTextField f : new JTextField[]{ fontField, preloadField } )
|
||||
{
|
||||
f.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
public void hide ()
|
||||
{
|
||||
frame.setVisible(false);
|
||||
}
|
||||
|
||||
void applyDirectives ()
|
||||
{
|
||||
findRemoveDirectives(true);
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
String head = "", toe = "; \n";
|
||||
|
||||
if ( crispBox.isSelected() )
|
||||
buffer.append( head + "crisp=true" + toe );
|
||||
if ( !fontField.getText().trim().equals("") )
|
||||
buffer.append( head + "font=\""+fontField.getText().trim()+"\"" + toe );
|
||||
if ( globalKeyEventsBox.isSelected() )
|
||||
buffer.append( head + "globalKeyEvents=true" + toe );
|
||||
if ( pauseOnBlurBox.isSelected() )
|
||||
buffer.append( head + "pauseOnBlur=true" + toe );
|
||||
if ( !preloadField.getText().trim().equals("") )
|
||||
buffer.append( head + "preload=\""+preloadField.getText().trim()+"\"" + toe );
|
||||
if ( transparentBox.isSelected() )
|
||||
buffer.append( head + "transparent=true" + toe );
|
||||
|
||||
Sketch sketch = editor.getSketch();
|
||||
SketchCode code = sketch.getCode(0); // first tab
|
||||
if ( buffer.length() > 0 )
|
||||
{
|
||||
code.setProgram( "/* @pjs " + buffer.toString() + " */\n\n" + code.getProgram() );
|
||||
if ( sketch.getCurrentCode() == code ) // update textarea if on first tab
|
||||
{
|
||||
editor.setText(sketch.getCurrentCode().getProgram());
|
||||
editor.setSelection(0,0);
|
||||
}
|
||||
|
||||
sketch.setModified( false );
|
||||
sketch.setModified( true );
|
||||
}
|
||||
}
|
||||
|
||||
void findRemoveDirectives ( boolean clean )
|
||||
{
|
||||
//if ( clean ) editor.startCompoundEdit();
|
||||
|
||||
Sketch sketch = editor.getSketch();
|
||||
for (int i = 0; i < sketch.getCodeCount(); i++)
|
||||
{
|
||||
SketchCode code = sketch.getCode(i);
|
||||
String program = code.getProgram();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
Matcher m = pjsPattern.matcher( program );
|
||||
while (m.find())
|
||||
{
|
||||
String mm = m.group();
|
||||
|
||||
/* remove framing */
|
||||
mm = mm.replaceAll("^\\/\\*\\s*@pjs","").replaceAll("\\s*\\*\\/\\s*$","");
|
||||
/* fix multiline version without semicolons */
|
||||
mm = mm.replaceAll("([^;\\s\\n\\r]+)[\\s]*[\\n\\r]+","$1;");
|
||||
mm = mm.replaceAll("\n","").replaceAll("\r","");
|
||||
|
||||
if ( clean )
|
||||
{
|
||||
m.appendReplacement(buffer, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
String[] directives = mm.split(";");
|
||||
for ( String d : directives )
|
||||
{
|
||||
//System.out.println(d);
|
||||
parseDirective(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( clean )
|
||||
{
|
||||
m.appendTail(buffer);
|
||||
|
||||
// TODO: not working!
|
||||
code.setProgram( buffer.toString() );
|
||||
code.setModified( true );
|
||||
}
|
||||
}
|
||||
|
||||
if ( clean )
|
||||
{
|
||||
//editor.stopCompoundEdit();
|
||||
editor.setText(sketch.getCurrentCode().getProgram());
|
||||
sketch.setModified( false );
|
||||
sketch.setModified( true );
|
||||
}
|
||||
}
|
||||
|
||||
private void parseDirective ( String directive )
|
||||
{
|
||||
if ( directive == null )
|
||||
{
|
||||
System.err.println( "Directive is null." );
|
||||
return;
|
||||
}
|
||||
|
||||
String[] pair = directive.split("=");
|
||||
if ( pair == null || pair.length != 2 )
|
||||
{
|
||||
System.err.println("Unable to parse directive: \"" + directive + "\" Ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
String key = pair[0].trim(), value = pair[1].trim();
|
||||
|
||||
if ( validKeys.indexOf(key) == -1 )
|
||||
{
|
||||
System.err.println("Directive key not recognized: \"" + key + "\" Ignored." );
|
||||
return;
|
||||
}
|
||||
if ( value.equals("") )
|
||||
{
|
||||
System.err.println("Directive value empty. Ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
value = value.replaceAll("^\"|\"$","").replaceAll("^'|'$","");
|
||||
|
||||
//System.out.println( key + " = " + value );
|
||||
|
||||
boolean v;
|
||||
switch ( validKeys.indexOf(key) )
|
||||
{
|
||||
case CRISP:
|
||||
v = value.toLowerCase().equals("true");
|
||||
crispBox.setSelected(v);
|
||||
break;
|
||||
case FONT:
|
||||
fontField.setText(value);
|
||||
break;
|
||||
case GLOBAL_KEY_EVENTS:
|
||||
v = value.toLowerCase().equals("true");
|
||||
globalKeyEventsBox.setSelected(v);
|
||||
break;
|
||||
case PAUSE_ON_BLUR:
|
||||
v = value.toLowerCase().equals("true");
|
||||
pauseOnBlurBox.setSelected(v);
|
||||
break;
|
||||
case PRELOAD:
|
||||
preloadField.setText(value);
|
||||
break;
|
||||
case TRANSPARENT:
|
||||
v = value.toLowerCase().equals("true");
|
||||
transparentBox.setSelected(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void createFrame ()
|
||||
{
|
||||
/* see Preferences.java */
|
||||
int GUI_BIG = 13;
|
||||
int GUI_BETWEEN = 10;
|
||||
int GUI_SMALL = 6;
|
||||
int FIELD_SIZE = 30;
|
||||
|
||||
int left = GUI_BIG;
|
||||
int top = GUI_BIG;
|
||||
int right = 0;
|
||||
|
||||
Dimension d;
|
||||
|
||||
frame = new JFrame("Directives Editor");
|
||||
Container pane = frame.getContentPane();
|
||||
pane.setLayout(null);
|
||||
|
||||
JLabel label = new JLabel("Click here to read about directives.");
|
||||
label.addMouseListener(new MouseListener(){
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
Base.openURL("http://processingjs.org/reference/pjs%20directive");
|
||||
}
|
||||
public void mouseEntered(MouseEvent e) {}
|
||||
public void mouseExited(MouseEvent e) {}
|
||||
public void mousePressed(MouseEvent e) {}
|
||||
public void mouseReleased(MouseEvent e) {}
|
||||
});
|
||||
pane.add(label);
|
||||
d = label.getPreferredSize();
|
||||
label.setBounds(left, top, d.width, d.height);
|
||||
top += d.height + GUI_BETWEEN + GUI_BETWEEN;
|
||||
|
||||
// CRISP
|
||||
|
||||
crispBox =
|
||||
new JCheckBox("\"crisp\": disable antialiasing for line(), triangle() and rect()");
|
||||
pane.add(crispBox);
|
||||
d = crispBox.getPreferredSize();
|
||||
crispBox.setBounds(left, top, d.width + 10, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
// FONTS
|
||||
|
||||
label = new JLabel("\"font\": to load: (comma separated)");
|
||||
pane.add(label);
|
||||
d = label.getPreferredSize();
|
||||
label.setBounds(left, top, d.width, d.height);
|
||||
top += d.height + GUI_SMALL;
|
||||
|
||||
fontField = new JTextField(FIELD_SIZE);
|
||||
pane.add(fontField);
|
||||
d = fontField.getPreferredSize();
|
||||
fontField.setBounds(left, top, d.width, d.height);
|
||||
|
||||
JButton button = new JButton("scan");
|
||||
button.addActionListener(new ActionListener(){
|
||||
public void actionPerformed (ActionEvent e) {
|
||||
handleScanFonts();
|
||||
}
|
||||
});
|
||||
pane.add(button);
|
||||
Dimension d2 = button.getPreferredSize();
|
||||
button.setBounds(left + d.width + GUI_SMALL, top, d2.width, d2.height);
|
||||
right = Math.max(right, left + d.width + GUI_SMALL + d2.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
// GLOBAL_KEY_EVENTS
|
||||
|
||||
globalKeyEventsBox =
|
||||
new JCheckBox("\"globalKeyEvents\": receive global key events");
|
||||
pane.add(globalKeyEventsBox);
|
||||
d = globalKeyEventsBox.getPreferredSize();
|
||||
globalKeyEventsBox.setBounds(left, top, d.width + 10, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
// PAUSE_ON_BLUR
|
||||
|
||||
pauseOnBlurBox =
|
||||
new JCheckBox("\"pauseOnBlur\": pause if applet loses focus");
|
||||
pane.add(pauseOnBlurBox);
|
||||
d = pauseOnBlurBox.getPreferredSize();
|
||||
pauseOnBlurBox.setBounds(left, top, d.width + 10, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
// PRELOAD images
|
||||
|
||||
label = new JLabel("\"preload\": images (comma separated)");
|
||||
pane.add(label);
|
||||
d = label.getPreferredSize();
|
||||
label.setBounds(left, top, d.width, d.height);
|
||||
top += d.height + GUI_SMALL;
|
||||
|
||||
preloadField = new JTextField(FIELD_SIZE);
|
||||
pane.add(preloadField);
|
||||
d = preloadField.getPreferredSize();
|
||||
preloadField.setBounds(left, top, d.width, d.height);
|
||||
|
||||
button = new JButton("scan");
|
||||
button.addActionListener(new ActionListener(){
|
||||
public void actionPerformed (ActionEvent e) {
|
||||
handleScanImages();
|
||||
}
|
||||
});
|
||||
pane.add(button);
|
||||
d2 = button.getPreferredSize();
|
||||
button.setBounds(left + d.width + GUI_SMALL, top, d2.width, d2.height);
|
||||
right = Math.max(right, left + d.width + GUI_SMALL + d2.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
// TRANSPARENT
|
||||
|
||||
transparentBox =
|
||||
new JCheckBox("\"transparent\": set applet background to be transparent");
|
||||
pane.add(transparentBox);
|
||||
d = transparentBox.getPreferredSize();
|
||||
transparentBox.setBounds(left, top, d.width + 10, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
// APPLY / OK
|
||||
|
||||
button = new JButton("OK");
|
||||
button.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
applyDirectives();
|
||||
hide();
|
||||
}
|
||||
});
|
||||
pane.add(button);
|
||||
d2 = button.getPreferredSize();
|
||||
int BUTTON_HEIGHT = d2.height;
|
||||
int BUTTON_WIDTH = 80;
|
||||
|
||||
int h = right - (BUTTON_WIDTH + GUI_SMALL + BUTTON_WIDTH);
|
||||
button.setBounds(h, top, BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
h += BUTTON_WIDTH + GUI_SMALL;
|
||||
|
||||
button = new JButton("Cancel");
|
||||
button.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
pane.add(button);
|
||||
button.setBounds(h, top, BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
|
||||
top += BUTTON_HEIGHT + GUI_BETWEEN;
|
||||
|
||||
//frame.getContentPane().add(box);
|
||||
frame.pack();
|
||||
Insets insets = frame.getInsets();
|
||||
frame.setSize(right + GUI_BIG + insets.left + insets.right,
|
||||
top + GUI_SMALL + insets.top + insets.bottom);
|
||||
|
||||
//frame.setResizable(false);
|
||||
|
||||
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
frame.setVisible(false);
|
||||
}
|
||||
});
|
||||
Base.registerWindowCloseKeys(frame.getRootPane(), new ActionListener() {
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
frame.setVisible(false);
|
||||
}
|
||||
});
|
||||
Base.setIcon(frame);
|
||||
}
|
||||
|
||||
void handleScanFonts()
|
||||
{
|
||||
handleScanFiles( fontField, new String[]{
|
||||
"woff", "svg", "eot", "ttf", "otf"
|
||||
});
|
||||
}
|
||||
|
||||
void handleScanImages()
|
||||
{
|
||||
handleScanFiles( preloadField, new String[]{
|
||||
"gif", "jpg", "jpeg", "png", "tga"
|
||||
});
|
||||
}
|
||||
|
||||
void handleScanFiles ( JTextField field, String[] extensions )
|
||||
{
|
||||
String[] dataFiles = scanDataFolderForFilesByType(extensions);
|
||||
if ( dataFiles == null || dataFiles.length == 0 )
|
||||
return;
|
||||
|
||||
String[] oldFileList = field.getText().trim().split(",");
|
||||
ArrayList<String> newFileList = new ArrayList<String>();
|
||||
for ( String c : oldFileList )
|
||||
{
|
||||
c = c.trim();
|
||||
if ( !c.equals("") && newFileList.indexOf(c) == -1 ) // TODO check exists() here?
|
||||
{
|
||||
newFileList.add( c );
|
||||
}
|
||||
}
|
||||
for ( String c : dataFiles )
|
||||
{
|
||||
c = c.trim();
|
||||
if ( !c.equals("") && newFileList.indexOf(c) == -1 )
|
||||
{
|
||||
newFileList.add( c );
|
||||
}
|
||||
}
|
||||
Collections.sort(newFileList);
|
||||
String finalFileList = ""; int i = 0;
|
||||
for ( String s : newFileList )
|
||||
{
|
||||
finalFileList += (i > 0 ? ", " : "") + s;
|
||||
i++;
|
||||
}
|
||||
field.setText(finalFileList);
|
||||
}
|
||||
|
||||
String[] scanDataFolderForFilesByType ( String[] extensions )
|
||||
{
|
||||
ArrayList files = new ArrayList();
|
||||
File dataFolder = editor.getSketch().getDataFolder();
|
||||
|
||||
if ( !dataFolder.exists() ) return null; // TODO no folder present .. warn?
|
||||
|
||||
for ( String ext : extensions )
|
||||
{
|
||||
String[] found = listFiles(dataFolder, true, ext);
|
||||
if ( found == null || found.length == 0 ) continue;
|
||||
|
||||
for ( String f : found )
|
||||
{
|
||||
if ( files.indexOf(f) == -1 )
|
||||
files.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
return (String[])files.toArray(new String[0]);
|
||||
}
|
||||
|
||||
// #718
|
||||
// http://code.google.com/p/processing/issues/detail?id=718
|
||||
private String[] listFiles(File folder, boolean relative, String extension) {
|
||||
String path = folder.getAbsolutePath();
|
||||
Vector<String> vector = new Vector<String>();
|
||||
if (extension != null) {
|
||||
if (!extension.startsWith(".")) {
|
||||
extension = "." + extension;
|
||||
}
|
||||
}
|
||||
listFiles(relative ? (path + File.separator) : "", path, extension, vector);
|
||||
String outgoing[] = new String[vector.size()];
|
||||
vector.copyInto(outgoing);
|
||||
return outgoing;
|
||||
}
|
||||
|
||||
|
||||
private void listFiles(String basePath,
|
||||
String path, String extension,
|
||||
Vector<String> vector) {
|
||||
File folder = new File(path);
|
||||
String[] list = folder.list();
|
||||
if (list != null) {
|
||||
for (String item : list) {
|
||||
if (item.charAt(0) == '.') continue;
|
||||
File file = new File(path, item);
|
||||
String newPath = file.getAbsolutePath();
|
||||
if (newPath.startsWith(basePath)) {
|
||||
newPath = newPath.substring(basePath.length());
|
||||
}
|
||||
if (extension == null || item.toLowerCase().endsWith(extension)) {
|
||||
vector.add(newPath);
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
listFiles(basePath, file.getAbsolutePath(), extension, vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,33 +4,41 @@ import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileWriter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.Mode;
|
||||
import processing.app.Sketch;
|
||||
import processing.app.SketchCode;
|
||||
import processing.app.SketchException;
|
||||
|
||||
import processing.core.PApplet;
|
||||
|
||||
import processing.mode.java.JavaBuild;
|
||||
import processing.mode.java.preproc.PdePreprocessor;
|
||||
import processing.mode.java.preproc.PreprocessorResult;
|
||||
|
||||
/**
|
||||
* A collection of static methods to aid in building a
|
||||
* web page with Processing.js from a Sketch object.
|
||||
*/
|
||||
public class JavaScriptBuild {
|
||||
|
||||
// public static final String SIZE_REGEX
|
||||
|
||||
// public static final String PACKAGE_REGEX
|
||||
public class JavaScriptBuild
|
||||
{
|
||||
public final static String TEMPLATE_FOLDER_NAME = "template_js";
|
||||
public final static String EXPORTED_FOLDER_NAME = "applet_js";
|
||||
public final static String TEMPLATE_FILE_NAME = "template.html";
|
||||
|
||||
/**
|
||||
* Answers with the first java doc style comment in the string,
|
||||
* or an empty string if no such comment can be found.
|
||||
*/
|
||||
public static String getDocString(String s) {
|
||||
public static String getDocString ( String s )
|
||||
{
|
||||
String[] javadoc = PApplet.match(s, "/\\*{2,}(.*?)\\*+/");
|
||||
if (javadoc != null) {
|
||||
|
||||
if (javadoc != null)
|
||||
{
|
||||
StringBuffer dbuffer = new StringBuffer();
|
||||
String[] pieces = PApplet.split(javadoc[1], '\n');
|
||||
for (String line : pieces) {
|
||||
@@ -58,9 +66,11 @@ public class JavaScriptBuild {
|
||||
* @param args template keys, data values to replace them
|
||||
* @throws IOException when there are problems writing to or from the files
|
||||
*/
|
||||
public static void writeTemplate(File template, File output, Map<String, String> fields) throws IOException {
|
||||
public static void writeTemplate ( File template, File output, Map<String, String> fields )
|
||||
throws IOException
|
||||
{
|
||||
BufferedReader reader = PApplet.createReader(template);
|
||||
PrintWriter theOutWriter = PApplet.createWriter(output);
|
||||
PrintWriter writer = PApplet.createWriter(output);
|
||||
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
@@ -80,9 +90,9 @@ public class JavaScriptBuild {
|
||||
}
|
||||
line = sb.toString();
|
||||
}
|
||||
theOutWriter.println(line);
|
||||
writer.println(line);
|
||||
}
|
||||
theOutWriter.close();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
@@ -100,8 +110,8 @@ public class JavaScriptBuild {
|
||||
|
||||
protected File binFolder;
|
||||
|
||||
|
||||
public JavaScriptBuild(Sketch sketch) {
|
||||
public JavaScriptBuild ( Sketch sketch )
|
||||
{
|
||||
this.sketch = sketch;
|
||||
this.mode = sketch.getMode();
|
||||
}
|
||||
@@ -116,32 +126,45 @@ public class JavaScriptBuild {
|
||||
* 3. cp -r sketch/data/* bin/ (p.js doesn't recognize the data folder)
|
||||
* 4. series of greps to find height, width, name, desc
|
||||
* 5. cat template.html | sed 's/@@sketch@@/[name]/g' ... [many sed filters] > bin/index.html
|
||||
* </p>
|
||||
*
|
||||
* @param bin the output folder for the built sketch
|
||||
* @return boolean whether the build was successful
|
||||
*/
|
||||
public boolean build(File bin) {
|
||||
public boolean build ( File bin )
|
||||
{
|
||||
// make sure the user isn't playing "hide-the-sketch-folder" again
|
||||
sketch.ensureExistence();
|
||||
|
||||
this.binFolder = bin;
|
||||
|
||||
if (bin.exists()) {
|
||||
if ( bin.exists() )
|
||||
{
|
||||
Base.removeDescendants(bin);
|
||||
} //else will be created during preprocesss
|
||||
|
||||
try {
|
||||
// pass through preprocessor to catch syntax errors
|
||||
try
|
||||
{
|
||||
preprocess(bin);
|
||||
} catch (IOException e) {
|
||||
final String msg = "A problem occured while writing to the output folder.";
|
||||
Base.showWarning("Could not build the sketch", msg, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// move the data files
|
||||
if (sketch.hasDataFolder()) {
|
||||
} catch ( IOException ioe ) {
|
||||
final String msg = "A problem occured while writing to the output folder.";
|
||||
Base.showWarning("Could not build the sketch", msg, ioe);
|
||||
return false;
|
||||
|
||||
} catch ( SketchException se ) {
|
||||
final String msg = "The preprocessor found a problem in your code.";
|
||||
Base.showWarning("Could not build the sketch", msg, se);
|
||||
return false;
|
||||
}
|
||||
|
||||
// move the data files, copies contents of sketch/data/ to applet_js/
|
||||
if (sketch.hasDataFolder())
|
||||
{
|
||||
try {
|
||||
Base.copyDir(sketch.getDataFolder(), bin);
|
||||
|
||||
} catch (IOException e) {
|
||||
final String msg = "An exception occured while trying to copy the data folder. " +
|
||||
"You may have to manually move the contents of sketch/data to " +
|
||||
@@ -151,20 +174,52 @@ public class JavaScriptBuild {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Code folder contents ending in .js could be moved and added as script tags?
|
||||
// as .js files are allowed now include these into the mix,
|
||||
// first find 'em ..
|
||||
String[] sketchFolderFilesRaw = sketch.getFolder().list();
|
||||
String[] sketchFolderFiles = new String[0];
|
||||
ArrayList sffList = new ArrayList();
|
||||
if ( sketchFolderFilesRaw != null )
|
||||
{
|
||||
for ( String s : sketchFolderFilesRaw )
|
||||
{
|
||||
if ( s.toLowerCase().startsWith(".") ) continue;
|
||||
if ( !s.toLowerCase().endsWith(".js") ) continue;
|
||||
sffList.add(s);
|
||||
}
|
||||
if ( sffList.size() > 0 )
|
||||
sketchFolderFiles = (String[])sffList.toArray(new String[0]);
|
||||
}
|
||||
for ( String s : sketchFolderFiles )
|
||||
{
|
||||
try {
|
||||
Base.copyFile( new File(sketch.getFolder(), s), new File(bin, s) );
|
||||
} catch ( IOException ioe ) {
|
||||
String msg = "Unable to copy file: "+s;
|
||||
Base.showWarning("Problem building the sketch", msg, ioe);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// get width and height
|
||||
int wide = PApplet.DEFAULT_WIDTH;
|
||||
int high = PApplet.DEFAULT_HEIGHT;
|
||||
|
||||
// TODO
|
||||
// Really scrub comments from code?
|
||||
// Con: larger files, PJS needs to do it later
|
||||
// Pro: being literate as we are in a script language.
|
||||
String scrubbed = JavaBuild.scrubComments(sketch.getCode(0).getProgram());
|
||||
String[] matches = PApplet.match(scrubbed, JavaBuild.SIZE_REGEX);
|
||||
|
||||
if (matches != null) {
|
||||
try {
|
||||
if (matches != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
wide = Integer.parseInt(matches[1]);
|
||||
high = Integer.parseInt(matches[2]);
|
||||
// renderer
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
// found a reference to size, but it didn't seem to contain numbers
|
||||
final String message =
|
||||
@@ -177,21 +232,47 @@ public class JavaScriptBuild {
|
||||
}
|
||||
} // else no size() command found, defaults will be used
|
||||
|
||||
// final prep and write to template
|
||||
File templateFile = sketch.getMode().getContentFile("applet_js/template.html");
|
||||
// final prep and write to template.
|
||||
// getTemplateFile() is very important as it looks and preps
|
||||
// any custom templates present in the sketch folder.
|
||||
File templateFile = getTemplateFile();
|
||||
File htmlOutputFile = new File(bin, "index.html");
|
||||
|
||||
|
||||
Map<String, String> templateFields = new HashMap<String, String>();
|
||||
templateFields.put("width", String.valueOf(wide));
|
||||
templateFields.put("height", String.valueOf(high));
|
||||
templateFields.put("sketch", sketch.getName());
|
||||
templateFields.put("description", getSketchDescription());
|
||||
templateFields.put("source",
|
||||
"<a href=\"" + sketch.getName() + ".pde\">" +
|
||||
sketch.getName() + "</a>");
|
||||
templateFields.put( "width", String.valueOf(wide) );
|
||||
templateFields.put( "height", String.valueOf(high) );
|
||||
templateFields.put( "sketch", sketch.getName() );
|
||||
templateFields.put( "description", getSketchDescription() );
|
||||
|
||||
try{
|
||||
// generate an ID for the sketch to use with <canvas id="XXXX"></canvas>
|
||||
String sketchID = sketch.getName().replaceAll("[^a-zA-Z0-9]+", "").replaceAll("^[^a-zA-Z]+","");
|
||||
// add a handy method to read the generated sketchID
|
||||
String scriptFiles = "<script type=\"text/javascript\">" +
|
||||
"function getProcessingSketchID () { return '"+sketchID+"'; }" +
|
||||
"</script>\n";
|
||||
|
||||
// main .pde file first
|
||||
String sourceFiles = "<a href=\"" + sketch.getName() + ".pde\">" +
|
||||
sketch.getName() + "</a> ";
|
||||
|
||||
// add all other files (both types: .pde and .js)
|
||||
if ( sketchFolderFiles != null )
|
||||
{
|
||||
for ( String s : sketchFolderFiles )
|
||||
{
|
||||
sourceFiles += "<a href=\"" + s + "\">" + s + "</a> ";
|
||||
scriptFiles += "<script src=\""+ s +"\" type=\"text/javascript\"></script>\n";
|
||||
}
|
||||
}
|
||||
templateFields.put( "source", sourceFiles );
|
||||
templateFields.put( "scripts", scriptFiles );
|
||||
templateFields.put( "id", sketchID );
|
||||
|
||||
// process template replace tokens with content
|
||||
try
|
||||
{
|
||||
writeTemplate(templateFile, htmlOutputFile, templateFields);
|
||||
|
||||
} catch (IOException ioe) {
|
||||
final String msg = "There was a problem writing the html template " +
|
||||
"to the build folder.";
|
||||
@@ -200,9 +281,14 @@ public class JavaScriptBuild {
|
||||
}
|
||||
|
||||
// finally, add Processing.js
|
||||
try {
|
||||
Base.copyFile(sketch.getMode().getContentFile("applet_js/processing.js"),
|
||||
new File(bin, "processing.js"));
|
||||
try
|
||||
{
|
||||
Base.copyFile( sketch.getMode().getContentFile(
|
||||
EXPORTED_FOLDER_NAME+"/processing.js"
|
||||
),
|
||||
new File( bin, "processing.js")
|
||||
);
|
||||
|
||||
} catch (IOException ioe) {
|
||||
final String msg = "There was a problem copying processing.js to the " +
|
||||
"build folder. You will have to manually add " +
|
||||
@@ -214,14 +300,59 @@ public class JavaScriptBuild {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and return the template HTML file to use. This also checks for custom
|
||||
* templates that might be living in the sketch folder. If such a "template_js"
|
||||
* folder exists then it's contents will be copied over to "applet_js" and
|
||||
* it's template.html will be used as template.
|
||||
*/
|
||||
private File getTemplateFile ()
|
||||
{
|
||||
File sketchFolder = sketch.getFolder();
|
||||
File customTemplateFolder = new File( sketchFolder, TEMPLATE_FOLDER_NAME );
|
||||
if ( customTemplateFolder.exists() &&
|
||||
customTemplateFolder.isDirectory() &&
|
||||
customTemplateFolder.canRead() )
|
||||
{
|
||||
File appletJsFolder = new File( sketchFolder, EXPORTED_FOLDER_NAME );
|
||||
|
||||
try {
|
||||
//TODO: this is potentially dangerous as it might override files in applet_js
|
||||
Base.copyDir( customTemplateFolder, appletJsFolder );
|
||||
if ( !(new File( appletJsFolder, TEMPLATE_FILE_NAME )).delete() )
|
||||
{
|
||||
// ignore?
|
||||
}
|
||||
return new File( customTemplateFolder, TEMPLATE_FILE_NAME );
|
||||
} catch ( Exception e ) {
|
||||
String msg = "";
|
||||
Base.showWarning("There was a problem copying your custom template folder", msg, e);
|
||||
return sketch.getMode().getContentFile(
|
||||
EXPORTED_FOLDER_NAME + File.separator + TEMPLATE_FILE_NAME
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
return sketch.getMode().getContentFile(
|
||||
EXPORTED_FOLDER_NAME + File.separator + TEMPLATE_FILE_NAME
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepares the sketch code objects for use with Processing.js
|
||||
* Collects the sketch code and runs it by the Java-mode preprocessor
|
||||
* to fish for errors.
|
||||
*
|
||||
* @param bin the output folder
|
||||
*
|
||||
* @see processing.mode.java.JavaBuild#preprocess(java.io.File)
|
||||
*/
|
||||
public void preprocess(File bin) throws IOException {
|
||||
public void preprocess ( File bin ) throws IOException, SketchException
|
||||
{
|
||||
// COLLECT .pde FILES INTO ONE,
|
||||
// essentially... cat sketchFolder/*.pde > bin/sketchname.pde
|
||||
|
||||
StringBuffer bigCode = new StringBuffer();
|
||||
for (SketchCode sc : sketch.getCode()){
|
||||
if (sc.isExtension("pde")) {
|
||||
@@ -234,9 +365,150 @@ public class JavaScriptBuild {
|
||||
bin.mkdirs();
|
||||
}
|
||||
File bigFile = new File(bin, sketch.getName() + ".pde");
|
||||
Base.saveFile(bigCode.toString(), bigFile);
|
||||
String bigCodeContents = bigCode.toString();
|
||||
Base.saveFile( bigCodeContents, bigFile );
|
||||
|
||||
// RUN THROUGH JAVA-MODE PREPROCESSOR,
|
||||
// some minor changes made since we are not running the result
|
||||
// but are only interested in any possible errors that may
|
||||
// surface
|
||||
|
||||
PdePreprocessor preprocessor = new PdePreprocessor( sketch.getName() );
|
||||
PreprocessorResult result;
|
||||
|
||||
try
|
||||
{
|
||||
File outputFolder = sketch.makeTempFolder();
|
||||
final File java = new File( outputFolder, sketch.getName() + ".java" );
|
||||
final PrintWriter stream = new PrintWriter( new FileWriter(java) );
|
||||
try {
|
||||
result = preprocessor.write( stream, bigCodeContents, null );
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
fnfe.printStackTrace();
|
||||
String msg = "Build folder disappeared or could not be written";
|
||||
throw new SketchException(msg);
|
||||
|
||||
} catch (antlr.RecognitionException re) {
|
||||
// re also returns a column that we're not bothering with for now
|
||||
|
||||
// first assume that it's the main file
|
||||
int errorLine = re.getLine() - 1;
|
||||
|
||||
// then search through for anyone else whose preprocName is null,
|
||||
// since they've also been combined into the main pde.
|
||||
int errorFile = findErrorFile(errorLine);
|
||||
errorLine -= sketch.getCode(errorFile).getPreprocOffset();
|
||||
|
||||
String msg = re.getMessage();
|
||||
|
||||
if (msg.equals("expecting RCURLY, found 'null'")) {
|
||||
// This can be a problem since the error is sometimes listed as a line
|
||||
// that's actually past the number of lines. For instance, it might
|
||||
// report "line 15" of a 14 line program. Added code to highlightLine()
|
||||
// inside Editor to deal with this situation (since that code is also
|
||||
// useful for other similar situations).
|
||||
throw new SketchException("Found one too many { characters " +
|
||||
"without a } to match it.",
|
||||
errorFile, errorLine, re.getColumn());
|
||||
}
|
||||
|
||||
if (msg.indexOf("expecting RBRACK") != -1) {
|
||||
System.err.println(msg);
|
||||
throw new SketchException("Syntax error, " +
|
||||
"maybe a missing ] character?",
|
||||
errorFile, errorLine, re.getColumn());
|
||||
}
|
||||
|
||||
if (msg.indexOf("expecting SEMI") != -1) {
|
||||
System.err.println(msg);
|
||||
throw new SketchException("Syntax error, " +
|
||||
"maybe a missing semicolon?",
|
||||
errorFile, errorLine, re.getColumn());
|
||||
}
|
||||
|
||||
if (msg.indexOf("expecting RPAREN") != -1) {
|
||||
System.err.println(msg);
|
||||
throw new SketchException("Syntax error, " +
|
||||
"maybe a missing right parenthesis?",
|
||||
errorFile, errorLine, re.getColumn());
|
||||
}
|
||||
|
||||
if (msg.indexOf("preproc.web_colors") != -1) {
|
||||
throw new SketchException("A web color (such as #ffcc00) " +
|
||||
"must be six digits.",
|
||||
errorFile, errorLine, re.getColumn(), false);
|
||||
}
|
||||
|
||||
//System.out.println("msg is " + msg);
|
||||
throw new SketchException(msg, errorFile,
|
||||
errorLine, re.getColumn());
|
||||
|
||||
} catch (antlr.TokenStreamRecognitionException tsre) {
|
||||
// while this seems to store line and column internally,
|
||||
// there doesn't seem to be a method to grab it..
|
||||
// so instead it's done using a regexp
|
||||
|
||||
// TODO not tested since removing ORO matcher.. ^ could be a problem
|
||||
String mess = "^line (\\d+):(\\d+):\\s";
|
||||
|
||||
String[] matches = PApplet.match(tsre.toString(), mess);
|
||||
if (matches != null) {
|
||||
int errorLine = Integer.parseInt(matches[1]) - 1;
|
||||
int errorColumn = Integer.parseInt(matches[2]);
|
||||
|
||||
int errorFile = 0;
|
||||
for (int i = 1; i < sketch.getCodeCount(); i++) {
|
||||
SketchCode sc = sketch.getCode(i);
|
||||
if (sc.isExtension("pde") &&
|
||||
(sc.getPreprocOffset() < errorLine)) {
|
||||
errorFile = i;
|
||||
}
|
||||
}
|
||||
errorLine -= sketch.getCode(errorFile).getPreprocOffset();
|
||||
|
||||
throw new SketchException(tsre.getMessage(),
|
||||
errorFile, errorLine, errorColumn);
|
||||
|
||||
} else {
|
||||
// this is bad, defaults to the main class.. hrm.
|
||||
String msg = tsre.toString();
|
||||
throw new SketchException(msg, 0, -1, -1);
|
||||
}
|
||||
|
||||
} catch (SketchException pe) {
|
||||
// RunnerExceptions are caught here and re-thrown, so that they don't
|
||||
// get lost in the more general "Exception" handler below.
|
||||
throw pe;
|
||||
|
||||
} catch (Exception ex) {
|
||||
// TODO better method for handling this?
|
||||
System.err.println("Uncaught exception type:" + ex.getClass());
|
||||
ex.printStackTrace();
|
||||
throw new SketchException(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from JavaBuild as it is protected there.
|
||||
* @see processing.mode.java.JavaBuild#findErrorFile(int)
|
||||
*/
|
||||
protected int findErrorFile ( int errorLine )
|
||||
{
|
||||
for (int i = 1; i < sketch.getCodeCount(); i++)
|
||||
{
|
||||
SketchCode sc = sketch.getCode(i);
|
||||
if (sc.isExtension("pde") && (sc.getPreprocOffset() < errorLine))
|
||||
{
|
||||
// keep looping until the errorLine is past the offset
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0; // i give up
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the sketch to retrieve it's description. Answers with the first
|
||||
@@ -256,9 +528,10 @@ public class JavaScriptBuild {
|
||||
* Export the sketch to the default applet_js folder.
|
||||
* @return success of the operation
|
||||
*/
|
||||
public boolean export() throws IOException {
|
||||
File applet_js = new File(sketch.getFolder(), "applet_js");
|
||||
return exportApplet_js(applet_js);
|
||||
public boolean export() throws IOException
|
||||
{
|
||||
File applet_js = new File(sketch.getFolder(), EXPORTED_FOLDER_NAME);
|
||||
return exportToFolder( applet_js );
|
||||
}
|
||||
|
||||
|
||||
@@ -266,7 +539,8 @@ public class JavaScriptBuild {
|
||||
* Export the sketch to the provided folder
|
||||
* @return success of the operation
|
||||
*/
|
||||
public boolean exportApplet_js(File appletfolder) throws IOException {
|
||||
return build(appletfolder);
|
||||
public boolean exportToFolder( File exportFolder ) throws IOException
|
||||
{
|
||||
return build( exportFolder );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,26 +11,49 @@ import javax.swing.JOptionPane;
|
||||
import processing.app.Base;
|
||||
import processing.app.Editor;
|
||||
import processing.app.EditorToolbar;
|
||||
import processing.app.Sketch;
|
||||
import processing.app.Formatter;
|
||||
import processing.app.Mode;
|
||||
import processing.mode.java.AutoFormat;
|
||||
import processing.mode.java.JavaEditor;
|
||||
|
||||
public class JavaScriptEditor extends Editor {
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class JavaScriptEditor extends Editor
|
||||
{
|
||||
|
||||
private JavaScriptMode jsMode;
|
||||
private JavaScriptServer jsServer;
|
||||
|
||||
|
||||
protected JavaScriptEditor(Base base, String path, int[] location, Mode mode) {
|
||||
private DirectivesEditor directivesEditor;
|
||||
|
||||
// TODO how to handle multiple servers
|
||||
// TODO read settings from sketch.properties
|
||||
// NOTE 0.0.0.0 does not work on XP
|
||||
private static final String localDomain = "http://127.0.0.1";
|
||||
|
||||
// tapping into Java mode might not be wanted?
|
||||
processing.mode.java.PdeKeyListener listener;
|
||||
|
||||
protected JavaScriptEditor ( Base base, String path, int[] location, Mode mode )
|
||||
{
|
||||
super(base, path, location, mode);
|
||||
|
||||
listener = new processing.mode.java.PdeKeyListener(this,textarea);
|
||||
|
||||
jsMode = (JavaScriptMode) mode;
|
||||
}
|
||||
|
||||
|
||||
public EditorToolbar createToolbar() {
|
||||
public EditorToolbar createToolbar ()
|
||||
{
|
||||
return new JavaScriptToolbar(this, base);
|
||||
}
|
||||
|
||||
|
||||
public Formatter createFormatter() {
|
||||
public Formatter createFormatter ()
|
||||
{
|
||||
return new AutoFormat();
|
||||
}
|
||||
|
||||
@@ -39,26 +62,79 @@ public class JavaScriptEditor extends Editor {
|
||||
// Menu methods
|
||||
|
||||
|
||||
public JMenu buildFileMenu() {
|
||||
public JMenu buildFileMenu ()
|
||||
{
|
||||
JMenuItem exportItem = Base.newJMenuItem("export title", 'E');
|
||||
exportItem.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
handleExport();
|
||||
handleExport( true );
|
||||
}
|
||||
});
|
||||
return buildFileMenu(new JMenuItem[] { exportItem });
|
||||
}
|
||||
|
||||
|
||||
public JMenu buildSketchMenu() {
|
||||
return buildSketchMenu(new JMenuItem[] {});
|
||||
public JMenu buildSketchMenu ()
|
||||
{
|
||||
JMenuItem startServerItem = Base.newJMenuItem("Start server", 'R');
|
||||
startServerItem.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
handleStartServer();
|
||||
}
|
||||
});
|
||||
|
||||
JMenuItem stopServerItem = new JMenuItem("Stop server");
|
||||
stopServerItem.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
handleStopServer();
|
||||
}
|
||||
});
|
||||
|
||||
JMenuItem showDirectivesWindow = new JMenuItem("Directives");
|
||||
showDirectivesWindow.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
handleShowDirectivesEditor();
|
||||
}
|
||||
});
|
||||
|
||||
JMenuItem copyTemplate = new JMenuItem("Copy template to sketch");
|
||||
copyTemplate.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Sketch sketch = getSketch();
|
||||
File ajs = sketch.getMode().getContentFile(JavaScriptBuild.EXPORTED_FOLDER_NAME);
|
||||
File tjs = new File( sketch.getFolder(), JavaScriptBuild.TEMPLATE_FOLDER_NAME );
|
||||
if ( !tjs.exists() )
|
||||
{
|
||||
try {
|
||||
Base.copyDir( ajs, tjs );
|
||||
statusNotice( "Default template copied." );
|
||||
Base.openFolder( tjs );
|
||||
} catch ( java.io.IOException ioe ) {
|
||||
Base.showWarning("Copy default template folder",
|
||||
"Something went wrong when copying the template folder.", ioe);
|
||||
}
|
||||
}
|
||||
else
|
||||
statusError( "You need to remove the current "+
|
||||
"\""+JavaScriptBuild.TEMPLATE_FOLDER_NAME+"\" "+
|
||||
"folder from the sketch." );
|
||||
}
|
||||
});
|
||||
|
||||
return buildSketchMenu(new JMenuItem[] {
|
||||
startServerItem, stopServerItem,
|
||||
showDirectivesWindow, copyTemplate
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public JMenu buildHelpMenu() {
|
||||
public JMenu buildHelpMenu ()
|
||||
{
|
||||
JMenu menu = new JMenu("Help ");
|
||||
JMenuItem item;
|
||||
|
||||
// TODO switch to "http://js.processing.org/"?
|
||||
|
||||
item = new JMenuItem("QuickStart for JS Devs");
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
@@ -108,13 +184,7 @@ public class JavaScriptEditor extends Editor {
|
||||
item = Base.newJMenuItemShift("Find in Reference", 'F');
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (textarea.isSelectionActive()) {
|
||||
Base.openURL(
|
||||
"http://www.google.com/search?q=" +
|
||||
textarea.getSelectedText() +
|
||||
"+site%3Ahttp%3A%2F%2Fprocessingjs.org%2Freference"
|
||||
);
|
||||
}
|
||||
handleFindReferenceHACK();
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
@@ -156,25 +226,129 @@ public class JavaScriptEditor extends Editor {
|
||||
// - - - - - - - - - - - - - - - - - -
|
||||
|
||||
|
||||
public String getCommentPrefix() {
|
||||
public String getCommentPrefix ()
|
||||
{
|
||||
return "//";
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - -
|
||||
|
||||
private void handleShowDirectivesEditor ()
|
||||
{
|
||||
if ( directivesEditor == null )
|
||||
{
|
||||
directivesEditor = new DirectivesEditor(this);
|
||||
}
|
||||
|
||||
directivesEditor.show();
|
||||
}
|
||||
|
||||
// this catches the textarea right-click events
|
||||
public void showReference( String filename )
|
||||
{
|
||||
// TODO: catch handleFindReference directly
|
||||
handleFindReferenceHACK();
|
||||
}
|
||||
|
||||
private void handleFindReferenceHACK ()
|
||||
{
|
||||
if (textarea.isSelectionActive()) {
|
||||
Base.openURL(
|
||||
"http://www.google.com/search?q=" +
|
||||
textarea.getSelectedText().trim() +
|
||||
"+site%3Ahttp%3A%2F%2Fprocessingjs.org%2Freference"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleStartStopServer ()
|
||||
{
|
||||
if ( jsServer != null && jsServer.isRunning())
|
||||
{
|
||||
handleStopServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
handleStartServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for RUN:
|
||||
* export to folder, start server, open in default browser.
|
||||
*/
|
||||
public void handleStartServer ()
|
||||
{
|
||||
handleExport( false );
|
||||
|
||||
File serverRoot = new File(sketch.getFolder(), JavaScriptBuild.EXPORTED_FOLDER_NAME);
|
||||
|
||||
// if server hung or something else went wrong .. stop it.
|
||||
if ( jsServer != null && (!jsServer.isRunning() || !jsServer.getRoot().equals(serverRoot)) )
|
||||
{
|
||||
jsServer.shutDown();
|
||||
jsServer = null;
|
||||
}
|
||||
|
||||
if ( jsServer == null )
|
||||
{
|
||||
jsServer = new JavaScriptServer( serverRoot );
|
||||
jsServer.start();
|
||||
System.out.println( "Server started." );
|
||||
|
||||
while ( !jsServer.isRunning() ) {}
|
||||
|
||||
String location = localDomain + ":" + jsServer.getPort() + "/";
|
||||
System.out.println( location );
|
||||
|
||||
if ( !System.getProperty("os.name").startsWith("Mac OS") )
|
||||
Base.openURL( location );
|
||||
else
|
||||
{
|
||||
try {
|
||||
String scpt = "osascript -e "+
|
||||
"\"tell application \\\"Finder\\\" to open location \\\"" + location + "\\\"\"";
|
||||
String[] cmd = { "/bin/bash", "-c", scpt };
|
||||
Process process = new ProcessBuilder( cmd ).start();
|
||||
} catch ( Exception e ) {
|
||||
Base.openURL( location );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( jsServer.isRunning() )
|
||||
{
|
||||
System.out.println( "Server running, reload your browser window." );
|
||||
System.out.println( localDomain + ":" + jsServer.getPort() + "/" );
|
||||
}
|
||||
toolbar.activate(JavaScriptToolbar.RUN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for STOP: stop server.
|
||||
*/
|
||||
public void handleStopServer ()
|
||||
{
|
||||
if ( jsServer != null && jsServer.isRunning() )
|
||||
jsServer.shutDown();
|
||||
|
||||
System.out.println("Server stopped.");
|
||||
toolbar.deactivate(JavaScriptToolbar.RUN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the export method of the sketch and handle the gui stuff
|
||||
*/
|
||||
public void handleExport() {
|
||||
public void handleExport ( boolean openFolder )
|
||||
{
|
||||
if (handleExportCheckModified()) {
|
||||
toolbar.activate(JavaScriptToolbar.EXPORT);
|
||||
try {
|
||||
boolean success = jsMode.handleExport(sketch);
|
||||
if (success) {
|
||||
File appletJSFolder = new File(sketch.getFolder(), "applet_js");
|
||||
if ( success && openFolder ) {
|
||||
File appletJSFolder = new File(sketch.getFolder(), JavaScriptBuild.EXPORTED_FOLDER_NAME );
|
||||
Base.openFolder(appletJSFolder);
|
||||
|
||||
statusNotice("Finished exporting.");
|
||||
} else {
|
||||
// error message already displayed by handleExport
|
||||
@@ -186,8 +360,34 @@ public class JavaScriptEditor extends Editor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changed from Editor.java to automaticaly export and
|
||||
* handle the server when it's running. Normal save ops otherwise.
|
||||
*/
|
||||
public boolean handleSaveRequest(boolean immediately)
|
||||
{
|
||||
if (untitled) {
|
||||
return handleSaveAs();
|
||||
// need to get the name, user might also cancel here
|
||||
|
||||
} else if (immediately) {
|
||||
handleSave();
|
||||
if ( jsServer != null && jsServer.isRunning() )
|
||||
handleStartServer();
|
||||
} else {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
handleSave();
|
||||
if ( jsServer != null && jsServer.isRunning() )
|
||||
handleStartServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handleExportCheckModified() {
|
||||
public boolean handleExportCheckModified ()
|
||||
{
|
||||
if (sketch.isModified()) {
|
||||
Object[] options = { "OK", "Cancel" };
|
||||
int result = JOptionPane.showOptionDialog(this,
|
||||
@@ -215,14 +415,16 @@ public class JavaScriptEditor extends Editor {
|
||||
}
|
||||
|
||||
|
||||
public void handleSave() {
|
||||
public void handleSave ()
|
||||
{
|
||||
toolbar.activate(JavaScriptToolbar.SAVE);
|
||||
super.handleSave();
|
||||
toolbar.deactivate(JavaScriptToolbar.SAVE);
|
||||
}
|
||||
|
||||
|
||||
public boolean handleSaveAs() {
|
||||
public boolean handleSaveAs ()
|
||||
{
|
||||
toolbar.activate(JavaScriptToolbar.SAVE);
|
||||
boolean result = super.handleSaveAs();
|
||||
toolbar.deactivate(JavaScriptToolbar.SAVE);
|
||||
@@ -230,18 +432,17 @@ public class JavaScriptEditor extends Editor {
|
||||
}
|
||||
|
||||
|
||||
public void handleImportLibrary(String item) {
|
||||
public void handleImportLibrary (String item)
|
||||
{
|
||||
Base.showWarning("Processing.js doesn't support libraries",
|
||||
"Libraries are not supported. Import statements are " +
|
||||
"ignored, and code relying on them will break.",
|
||||
null);
|
||||
}
|
||||
|
||||
|
||||
/** JavaScript mode has no runner. This method is empty. */
|
||||
public void internalCloseRunner() { }
|
||||
|
||||
public void internalCloseRunner () { }
|
||||
|
||||
/** JavaScript mode does not run anything. This method is empty. */
|
||||
public void deactivateRun() { }
|
||||
public void deactivateRun () { }
|
||||
}
|
||||
|
||||
@@ -13,19 +13,16 @@ import processing.app.syntax.PdeKeywords;
|
||||
import processing.core.PApplet;
|
||||
|
||||
/**
|
||||
* JS Mode is very simple. Since P.js is dependent on a browser there is
|
||||
* no runner, just an export so that users can debug in the browser of their
|
||||
* choice.
|
||||
* JS Mode for Processing based on Processing.js. Comes with a server as
|
||||
* replacement for the normal runner.
|
||||
*/
|
||||
public class JavaScriptMode extends Mode {
|
||||
|
||||
|
||||
// create a new editor with the mode
|
||||
public Editor createEditor(Base base, String path, int[] location) {
|
||||
return new JavaScriptEditor(base, path, location, this);
|
||||
}
|
||||
|
||||
|
||||
public JavaScriptMode(Base base, File folder) {
|
||||
super(base, folder);
|
||||
|
||||
@@ -37,7 +34,6 @@ public class JavaScriptMode extends Mode {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void loadKeywords() throws IOException {
|
||||
File file = new File(folder, "keywords.txt");
|
||||
BufferedReader reader = PApplet.createReader(file);
|
||||
@@ -102,16 +98,16 @@ public class JavaScriptMode extends Mode {
|
||||
return "pde";
|
||||
}
|
||||
|
||||
|
||||
// all file extensions it supports
|
||||
public String[] getExtensions() {
|
||||
return new String[] {"pde", "pjs"};
|
||||
return new String[] {"pde", "js"};
|
||||
}
|
||||
|
||||
|
||||
public String[] getIgnorable() {
|
||||
return new String[] {
|
||||
"applet_js" // not sure what color to paint this bike shed
|
||||
"applet",
|
||||
"applet_js",
|
||||
"template_js"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
692
app/src/processing/mode/javascript/JavaScriptServer.java
Normal file
692
app/src/processing/mode/javascript/JavaScriptServer.java
Normal file
@@ -0,0 +1,692 @@
|
||||
package processing.mode.javascript;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Based on Sun tutorial at: http://bit.ly/fpoHAF
|
||||
*
|
||||
* Changed to accept a document root.
|
||||
*/
|
||||
class JavaScriptServer implements HttpConstants, Runnable
|
||||
{
|
||||
Thread thread = null;
|
||||
ServerSocket server = null;
|
||||
|
||||
private ArrayList<Worker> threads = new ArrayList<Worker>();
|
||||
private int workers = 5;
|
||||
|
||||
private File virtualRoot;
|
||||
private int timeout = 5000;
|
||||
private int port = 0; /* using whatever port is available */
|
||||
|
||||
private boolean running = false, inited = false;
|
||||
private boolean stopping = false;
|
||||
|
||||
JavaScriptServer ( File root )
|
||||
{
|
||||
if ( virtualRoot == null && root.exists() && root.canRead() )
|
||||
{
|
||||
virtualRoot = root;
|
||||
}
|
||||
}
|
||||
|
||||
public File getRoot ()
|
||||
{
|
||||
return virtualRoot;
|
||||
}
|
||||
|
||||
public void setRoot ( File root )
|
||||
{
|
||||
virtualRoot = root;
|
||||
}
|
||||
|
||||
public int getTimeout ()
|
||||
{
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public int getPort ()
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
public void start ()
|
||||
{
|
||||
thread = null;
|
||||
thread = new Thread(this, "ProcessingJSServer");
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void restart ()
|
||||
{
|
||||
if ( running )
|
||||
shutDown();
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
// http://bit.ly/eA8iGj
|
||||
public void shutDown ()
|
||||
{
|
||||
if ( threads != null )
|
||||
{
|
||||
for ( Worker w : threads )
|
||||
{
|
||||
w.stop();
|
||||
}
|
||||
}
|
||||
|
||||
thread = null;
|
||||
try {
|
||||
if ( server != null )
|
||||
server.close();
|
||||
} catch ( Exception e ) {;}
|
||||
}
|
||||
|
||||
public boolean isRunning ()
|
||||
{
|
||||
return running && inited;
|
||||
}
|
||||
|
||||
public void run ()
|
||||
{
|
||||
if ( virtualRoot == null )
|
||||
{
|
||||
System.err.println( "ProcessingJSServer: virtual root is null." );
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
running = true;
|
||||
server = new ServerSocket( 0 );
|
||||
|
||||
port = server.getLocalPort();
|
||||
|
||||
inited = true;
|
||||
|
||||
while ( thread != null )
|
||||
{
|
||||
Socket s = server.accept();
|
||||
|
||||
Worker ws = new Worker( virtualRoot );
|
||||
ws.setSocket(s);
|
||||
(new Thread(ws, "ProcessingJSServer Worker")).start();
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
//ioe.printStackTrace();
|
||||
}
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Worker extends JavaScriptServer
|
||||
implements HttpConstants, Runnable
|
||||
{
|
||||
final static int BUF_SIZE = 2048;
|
||||
|
||||
static final byte[] EOL = {(byte)'\r', (byte)'\n' };
|
||||
|
||||
/* buffer to use for requests */
|
||||
byte[] buf;
|
||||
/* Socket to client we're handling */
|
||||
private Socket s;
|
||||
|
||||
private boolean stopping = false;
|
||||
|
||||
Worker ( File root )
|
||||
{
|
||||
super( root );
|
||||
buf = new byte[BUF_SIZE];
|
||||
s = null;
|
||||
}
|
||||
|
||||
synchronized void setSocket( Socket s )
|
||||
{
|
||||
this.s = s;
|
||||
notify();
|
||||
}
|
||||
|
||||
void stop ()
|
||||
{
|
||||
stopping = true;
|
||||
notify();
|
||||
}
|
||||
|
||||
public synchronized void run ()
|
||||
{
|
||||
while ( true && !stopping )
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
/* nothing to do */
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
/* should not happen */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( s != null && !stopping )
|
||||
{
|
||||
try {
|
||||
handleClient();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
s = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void handleClient() throws IOException {
|
||||
InputStream is = new BufferedInputStream(s.getInputStream());
|
||||
PrintStream ps = new PrintStream(s.getOutputStream());
|
||||
/* we will only block in read for this many milliseconds
|
||||
* before we fail with java.io.InterruptedIOException,
|
||||
* at which point we will abandon the connection.
|
||||
*/
|
||||
s.setSoTimeout( getTimeout() );
|
||||
s.setTcpNoDelay(true);
|
||||
/* zero out the buffer from last time */
|
||||
for (int i = 0; i < BUF_SIZE; i++) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
try {
|
||||
/* We only support HTTP GET/HEAD, and don't
|
||||
* support any fancy HTTP options,
|
||||
* so we're only interested really in
|
||||
* the first line.
|
||||
*/
|
||||
int nread = 0, r = 0;
|
||||
|
||||
outerloop:
|
||||
while (nread < BUF_SIZE) {
|
||||
r = is.read(buf, nread, BUF_SIZE - nread);
|
||||
if (r == -1) {
|
||||
/* EOF */
|
||||
return;
|
||||
}
|
||||
int i = nread;
|
||||
nread += r;
|
||||
for (; i < nread; i++) {
|
||||
if (buf[i] == (byte)'\n' || buf[i] == (byte)'\r') {
|
||||
/* read one line */
|
||||
break outerloop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* are we doing a GET or just a HEAD */
|
||||
boolean doingGet;
|
||||
/* beginning of file name */
|
||||
int index;
|
||||
if (buf[0] == (byte)'G' &&
|
||||
buf[1] == (byte)'E' &&
|
||||
buf[2] == (byte)'T' &&
|
||||
buf[3] == (byte)' ') {
|
||||
doingGet = true;
|
||||
index = 4;
|
||||
} else if (buf[0] == (byte)'H' &&
|
||||
buf[1] == (byte)'E' &&
|
||||
buf[2] == (byte)'A' &&
|
||||
buf[3] == (byte)'D' &&
|
||||
buf[4] == (byte)' ') {
|
||||
doingGet = false;
|
||||
index = 5;
|
||||
} else {
|
||||
/* we don't support this method */
|
||||
ps.print("HTTP/1.0 " + HTTP_BAD_METHOD +
|
||||
" unsupported method type: ");
|
||||
ps.write(buf, 0, 5);
|
||||
ps.write(EOL);
|
||||
ps.flush();
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
/* find the file name, from:
|
||||
* GET /foo/bar.html HTTP/1.0
|
||||
* extract "/foo/bar.html"
|
||||
*/
|
||||
for (i = index; i < nread; i++) {
|
||||
if (buf[i] == (byte)' ') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
String fname = (new String(buf, 0, index, i-index)).replace('/', File.separatorChar);
|
||||
if (fname.startsWith(File.separator))
|
||||
{
|
||||
fname = fname.substring(1);
|
||||
}
|
||||
fname = java.net.URLDecoder.decode(fname);
|
||||
File targ = new File( getRoot(), fname );
|
||||
if (targ.isDirectory())
|
||||
{
|
||||
File ind = new File(targ, "index.html");
|
||||
if (ind.exists()) {
|
||||
targ = ind;
|
||||
}
|
||||
}
|
||||
boolean OK = printHeaders(targ, ps);
|
||||
if (doingGet)
|
||||
{
|
||||
if (OK) {
|
||||
sendFile(targ, ps);
|
||||
} else {
|
||||
send404(targ, ps);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
||||
boolean printHeaders(File targ, PrintStream ps) throws IOException {
|
||||
boolean ret = false;
|
||||
int rCode = 0;
|
||||
if (!targ.exists()) {
|
||||
rCode = HTTP_NOT_FOUND;
|
||||
ps.print("HTTP/1.0 " + HTTP_NOT_FOUND + " not found");
|
||||
ps.write(EOL);
|
||||
ret = false;
|
||||
} else {
|
||||
rCode = HTTP_OK;
|
||||
ps.print("HTTP/1.0 " + HTTP_OK+" OK");
|
||||
ps.write(EOL);
|
||||
ret = true;
|
||||
}
|
||||
//System.out.println( "From " +s.getInetAddress().getHostAddress()+": GET " +
|
||||
// targ.getAbsolutePath()+" --> "+rCode);
|
||||
|
||||
ps.print("Server: Simple java");
|
||||
ps.write(EOL);
|
||||
ps.print("Date: " + (new Date()));
|
||||
ps.write(EOL);
|
||||
if (ret) {
|
||||
if (!targ.isDirectory()) {
|
||||
ps.print("Content-length: "+targ.length());
|
||||
ps.write(EOL);
|
||||
ps.print("Last Modified: " + (new
|
||||
Date(targ.lastModified())));
|
||||
ps.write(EOL);
|
||||
String name = targ.getName();
|
||||
int ind = name.lastIndexOf('.');
|
||||
String ct = null;
|
||||
if (ind > 0) {
|
||||
ct = (String) map.get(name.substring(ind));
|
||||
}
|
||||
if (ct == null) {
|
||||
ct = "unknown/unknown";
|
||||
}
|
||||
ps.print("Content-type: " + ct);
|
||||
ps.write(EOL);
|
||||
} else {
|
||||
ps.print("Content-type: text/html");
|
||||
ps.write(EOL);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void send404(File targ, PrintStream ps) throws IOException {
|
||||
ps.write(EOL);
|
||||
ps.write(EOL);
|
||||
ps.println("Not Found\n\n"+
|
||||
"The requested resource was not found.\n");
|
||||
}
|
||||
|
||||
void sendFile(File targ, PrintStream ps) throws IOException {
|
||||
InputStream is = null;
|
||||
ps.write(EOL);
|
||||
if (targ.isDirectory()) {
|
||||
listDirectory(targ, ps);
|
||||
return;
|
||||
} else {
|
||||
is = new FileInputStream(targ.getAbsolutePath());
|
||||
}
|
||||
|
||||
try {
|
||||
int n;
|
||||
while ((n = is.read(buf)) > 0) {
|
||||
ps.write(buf, 0, n);
|
||||
}
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
/* mapping of file extensions to content-types */
|
||||
static java.util.Hashtable map = new java.util.Hashtable();
|
||||
|
||||
static {
|
||||
fillMap();
|
||||
}
|
||||
|
||||
static void setSuffix(String k, String v) {
|
||||
map.put(k, v);
|
||||
}
|
||||
|
||||
static void fillMap()
|
||||
{
|
||||
// this probably can be shortened a lot since this is not a normal server ..
|
||||
setSuffix("", "content/unknown");
|
||||
setSuffix(".3dm", "x-world/x-3dmf");
|
||||
setSuffix(".3dmf", "x-world/x-3dmf");
|
||||
setSuffix(".ai", "application/pdf");
|
||||
setSuffix(".aif", "audio/x-aiff");
|
||||
setSuffix(".aifc", "audio/x-aiff");
|
||||
setSuffix(".aiff", "audio/x-aiff");
|
||||
setSuffix(".asc", "text/plain");
|
||||
setSuffix(".asd", "application/astound");
|
||||
setSuffix(".asn", "application/astound");
|
||||
setSuffix(".atom", "application/atom+xml");
|
||||
setSuffix(".au", "audio/basic");
|
||||
setSuffix(".avi", "video/x-msvideo");
|
||||
setSuffix(".avi", "video/x-msvideo");
|
||||
setSuffix(".bcpio", "application/x-bcpio");
|
||||
setSuffix(".bin", "application/octet-stream");
|
||||
setSuffix(".bmp", "image/bmp");
|
||||
setSuffix(".c", "text/plain");
|
||||
setSuffix(".c++", "text/plain");
|
||||
setSuffix(".cab", "application/x-shockwave-flash");
|
||||
setSuffix(".cc", "text/plain");
|
||||
setSuffix(".cdf", "application/x-netcdf");
|
||||
setSuffix(".cgm", "image/cgm");
|
||||
setSuffix(".chm", "application/mshelp");
|
||||
setSuffix(".cht", "audio/x-dspeeh");
|
||||
setSuffix(".class", "application/octet-stream");
|
||||
setSuffix(".cod", "image/cis-cod");
|
||||
setSuffix(".com", "application/octet-stream");
|
||||
setSuffix(".cpio", "application/x-cpio");
|
||||
setSuffix(".cpt", "application/mac-compactpro");
|
||||
setSuffix(".csh", "application/x-csh");
|
||||
setSuffix(".css", "text/css");
|
||||
setSuffix(".csv", "text/comma-separated-values");
|
||||
setSuffix(".dcr", "application/x-director");
|
||||
setSuffix(".dif", "video/x-dv");
|
||||
setSuffix(".dir", "application/x-director");
|
||||
setSuffix(".djv", "image/vnd.djvu");
|
||||
setSuffix(".djvu", "image/vnd.djvu");
|
||||
setSuffix(".dll", "application/octet-stream");
|
||||
setSuffix(".dmg", "application/octet-stream");
|
||||
setSuffix(".dms", "application/octet-stream");
|
||||
setSuffix(".doc", "application/msword");
|
||||
setSuffix(".dot", "application/msword");
|
||||
setSuffix(".dtd", "application/xml-dtd");
|
||||
setSuffix(".dus", "audio/x-dspeeh");
|
||||
setSuffix(".dv", "video/x-dv");
|
||||
setSuffix(".dvi", "application/x-dvi");
|
||||
setSuffix(".dwf", "drawing/x-dwf");
|
||||
setSuffix(".dwg", "application/acad");
|
||||
setSuffix(".dxf", "application/dxf");
|
||||
setSuffix(".dxr", "application/x-director");
|
||||
setSuffix(".eps", "application/pdf");
|
||||
setSuffix(".es", "audio/echospeech");
|
||||
setSuffix(".etx", "text/x-setext");
|
||||
setSuffix(".etx", "text/x-setext");
|
||||
setSuffix(".evy", "application/x-envoy");
|
||||
setSuffix(".exe", "application/octet-stream");
|
||||
setSuffix(".ez", "application/andrew-inset");
|
||||
setSuffix(".fh4", "image/x-freehand");
|
||||
setSuffix(".fh5", "image/x-freehand");
|
||||
setSuffix(".fhc", "image/x-freehand");
|
||||
setSuffix(".fif", "image/fif");
|
||||
setSuffix(".gif", "image/gif");
|
||||
setSuffix(".gram", "application/srgs");
|
||||
setSuffix(".grxml", "application/srgs+xml");
|
||||
setSuffix(".gtar", "application/x-gtar");
|
||||
setSuffix(".gtar", "application/x-gtar");
|
||||
setSuffix(".gz", "application/gzip");
|
||||
setSuffix(".h", "text/plain");
|
||||
setSuffix(".hdf", "application/x-hdf");
|
||||
setSuffix(".hlp", "application/mshelp");
|
||||
setSuffix(".hqx", "application/mac-binhex40");
|
||||
setSuffix(".htm", "text/html");
|
||||
setSuffix(".html", "text/html");
|
||||
setSuffix(".ice", "x-conference/x-cooltalk");
|
||||
setSuffix(".ico", "image/x-icon");
|
||||
setSuffix(".ics", "text/calendar");
|
||||
setSuffix(".ief", "image/ief");
|
||||
setSuffix(".ifb", "text/calendar");
|
||||
setSuffix(".iges", "model/iges");
|
||||
setSuffix(".igs", "model/iges");
|
||||
setSuffix(".java", "text/plain");
|
||||
setSuffix(".jnlp", "application/x-java-jnlp-file");
|
||||
setSuffix(".jp2", "image/jp2");
|
||||
setSuffix(".jpe", "image/jpeg");
|
||||
setSuffix(".jpeg", "image/jpeg");
|
||||
setSuffix(".jpg", "image/jpeg");
|
||||
setSuffix(".js", "text/javascript");
|
||||
setSuffix(".kar", "audio/midi");
|
||||
setSuffix(".latex", "application/x-latex");
|
||||
setSuffix(".latex", "application/x-latex");
|
||||
setSuffix(".lha", "application/octet-stream");
|
||||
setSuffix(".lzh", "application/octet-stream");
|
||||
setSuffix(".m3u", "audio/x-mpegurl");
|
||||
setSuffix(".m4a", "audio/mp4a-latm");
|
||||
setSuffix(".m4b", "audio/mp4a-latm");
|
||||
setSuffix(".m4p", "audio/mp4a-latm");
|
||||
setSuffix(".m4u", "video/vnd.mpegurl");
|
||||
setSuffix(".m4v", "video/x-m4v");
|
||||
setSuffix(".mac", "image/x-macpaint");
|
||||
setSuffix(".man", "application/x-troff-man");
|
||||
setSuffix(".mathml", "application/mathml+xml");
|
||||
setSuffix(".mbd", "application/mbedlet");
|
||||
setSuffix(".mcf", "image/vasa");
|
||||
setSuffix(".me", "application/x-troff-me");
|
||||
setSuffix(".mesh", "model/mesh");
|
||||
setSuffix(".mid", "audio/midi");
|
||||
setSuffix(".midi", "audio/midi");
|
||||
setSuffix(".mif", "application/mif");
|
||||
setSuffix(".mov", "video/quicktime");
|
||||
setSuffix(".movie", "video/x-sgi-movie");
|
||||
setSuffix(".mp2", "audio/mpeg");
|
||||
setSuffix(".mp3", "audio/mpeg");
|
||||
setSuffix(".mp4", "video/mp4");
|
||||
setSuffix(".mpe", "video/mpeg");
|
||||
setSuffix(".mpeg", "video/mpeg");
|
||||
setSuffix(".mpg", "video/mpeg");
|
||||
setSuffix(".mpga", "audio/mpeg");
|
||||
setSuffix(".ms", "application/x-troff-ms");
|
||||
setSuffix(".msh", "model/mesh");
|
||||
setSuffix(".mxu", "video/vnd.mpegurl");
|
||||
setSuffix(".nc", "application/x-netcdf");
|
||||
setSuffix(".nsc", "application/x-nschat");
|
||||
setSuffix(".oda", "application/oda");
|
||||
setSuffix(".oga", "audio/ogg");
|
||||
setSuffix(".ogg", "application/ogg");
|
||||
setSuffix(".ogv", "video/ogg");
|
||||
setSuffix(".pbm", "image/x-portable-bitmap");
|
||||
setSuffix(".pct", "image/pict");
|
||||
setSuffix(".pdb", "chemical/x-pdb");
|
||||
setSuffix(".pde", "text/plain");
|
||||
setSuffix(".pdf", "application/pdf");
|
||||
setSuffix(".pgm", "image/x-portable-graymap");
|
||||
setSuffix(".pgn", "application/x-chess-pgn");
|
||||
setSuffix(".php", "application/x-httpd-php");
|
||||
setSuffix(".phtml", "application/x-httpd-php");
|
||||
setSuffix(".pic", "image/pict");
|
||||
setSuffix(".pict", "image/pict");
|
||||
setSuffix(".pl", "text/plain");
|
||||
setSuffix(".png", "image/png");
|
||||
setSuffix(".pnm", "image/x-portable-anymap");
|
||||
setSuffix(".pnt", "image/x-macpaint");
|
||||
setSuffix(".pntg", "image/x-macpaint");
|
||||
setSuffix(".pot", "application/mspowerpoint");
|
||||
setSuffix(".ppm", "image/x-portable-pixmap");
|
||||
setSuffix(".pps", "application/mspowerpoint");
|
||||
setSuffix(".ppt", "application/mspowerpoint");
|
||||
setSuffix(".ppz", "application/mspowerpoint");
|
||||
setSuffix(".ps", "application/postscript");
|
||||
setSuffix(".ps", "application/postscript");
|
||||
setSuffix(".ptlk", "application/listenup");
|
||||
setSuffix(".qd3", "x-world/x-3dmf");
|
||||
setSuffix(".qd3d", "x-world/x-3dmf");
|
||||
setSuffix(".qt", "video/quicktime");
|
||||
setSuffix(".qti", "image/x-quicktime");
|
||||
setSuffix(".qtif", "image/x-quicktime");
|
||||
setSuffix(".ra", "audio/x-pn-realaudio");
|
||||
setSuffix(".ra", "audio/x-pn-realaudio");
|
||||
setSuffix(".ram", "audio/x-mpeg");
|
||||
setSuffix(".ras", "image/cmu-raster");
|
||||
setSuffix(".rdf", "application/rdf+xml");
|
||||
setSuffix(".rgb", "image/x-rgb");
|
||||
setSuffix(".rm", "application/vnd.rn-realmedia");
|
||||
setSuffix(".roff", "application/x-troff");
|
||||
setSuffix(".rpm", "audio/x-pn-realaudio-plugin");
|
||||
setSuffix(".rtc", "application/rtc");
|
||||
setSuffix(".rtf", "text/rtf");
|
||||
setSuffix(".rtx", "text/richtext");
|
||||
setSuffix(".sca", "application/x-supercard");
|
||||
setSuffix(".sgm", "text/sgml");
|
||||
setSuffix(".sgml", "text/sgml");
|
||||
setSuffix(".sh", "application/x-sh");
|
||||
setSuffix(".shar", "application/x-shar");
|
||||
setSuffix(".shtml", "text/html");
|
||||
setSuffix(".silo", "model/mesh");
|
||||
setSuffix(".sit", "application/x-stuffit");
|
||||
setSuffix(".skd", "application/x-koan");
|
||||
setSuffix(".skm", "application/x-koan");
|
||||
setSuffix(".skp", "application/x-koan");
|
||||
setSuffix(".skt", "application/x-koan");
|
||||
setSuffix(".smi", "application/smil");
|
||||
setSuffix(".smil", "application/smil");
|
||||
setSuffix(".smp", "application/studiom");
|
||||
setSuffix(".snd", "audio/basic");
|
||||
setSuffix(".so", "application/octet-stream");
|
||||
setSuffix(".spc", "text/x-speech");
|
||||
setSuffix(".spl", "application/futuresplash");
|
||||
setSuffix(".spr", "application/x-sprite");
|
||||
setSuffix(".sprite", "application/x-sprite");
|
||||
setSuffix(".src", "application/x-wais-source");
|
||||
setSuffix(".stream", "audio/x-qt-stream");
|
||||
setSuffix(".sv4cpio", "application/x-sv4cpio");
|
||||
setSuffix(".sv4crc", "application/x-sv4crc");
|
||||
setSuffix(".svg", "image/svg+xml");
|
||||
setSuffix(".swf", "application/x-shockwave-flash");
|
||||
setSuffix(".t", "application/x-troff");
|
||||
setSuffix(".talk", "text/x-speech");
|
||||
setSuffix(".tar", "application/x-tar");
|
||||
setSuffix(".tbk", "application/toolbook");
|
||||
setSuffix(".tcl", "application/x-tcl");
|
||||
setSuffix(".tex", "application/x-tex");
|
||||
setSuffix(".texi", "application/x-texinfo");
|
||||
setSuffix(".texinfo", "text/plain");
|
||||
setSuffix(".text", "text/plain");
|
||||
setSuffix(".tif", "image/tiff");
|
||||
setSuffix(".tiff", "image/tiff");
|
||||
setSuffix(".tr", "application/x-troff");
|
||||
setSuffix(".troff", "application/x-troff-man");
|
||||
setSuffix(".tsi", "audio/tsplayer");
|
||||
setSuffix(".tsp", "application/dsptype");
|
||||
setSuffix(".tsv", "text/tab-separated-values");
|
||||
setSuffix(".tsv", "text/tab-separated-values");
|
||||
setSuffix(".txt", "text/plain");
|
||||
setSuffix(".ustar", "application/x-ustar");
|
||||
setSuffix(".uu", "application/octet-stream");
|
||||
setSuffix(".vcd", "application/x-cdlink");
|
||||
setSuffix(".viv", "video/vnd.vivo");
|
||||
setSuffix(".vivo", "video/vnd.vivo");
|
||||
setSuffix(".vmd", "application/vocaltec-media-desc");
|
||||
setSuffix(".vmf", "application/vocaltec-media-file");
|
||||
setSuffix(".vox", "audio/voxware");
|
||||
setSuffix(".vrml", "model/vrml");
|
||||
setSuffix(".vts", "workbook/formulaone");
|
||||
setSuffix(".vtts", "workbook/formulaone");
|
||||
setSuffix(".vxml", "application/voicexml+xml");
|
||||
setSuffix(".wav", "audio/x-wav");
|
||||
setSuffix(".wav", "audio/x-wav");
|
||||
setSuffix(".wbmp", "image/vnd.wap.wbmp");
|
||||
setSuffix(".wbmxl", "application/vnd.wap.wbxml");
|
||||
setSuffix(".wml", "text/vnd.wap.wml");
|
||||
setSuffix(".wmlc", "application/vnd.wap.wmlc");
|
||||
setSuffix(".wmls", "text/vnd.wap.wmlscript");
|
||||
setSuffix(".wmlsc", "application/vnd.wap.wmlscriptc");
|
||||
setSuffix(".wrl", "model/vrml");
|
||||
setSuffix(".xbm", "image/x-xbitmap");
|
||||
setSuffix(".xht", "application/xhtml+xml");
|
||||
setSuffix(".xhtml", "application/xhtml+xml");
|
||||
setSuffix(".xla", "application/msexcel");
|
||||
setSuffix(".xls", "application/msexcel");
|
||||
setSuffix(".xml", "text/xml");
|
||||
setSuffix(".xpm", "image/x-xpixmap");
|
||||
setSuffix(".xsl", "application/xml");
|
||||
setSuffix(".xslt", "application/xslt+xml");
|
||||
setSuffix(".xul", "application/vnd.mozilla.xul+xml");
|
||||
setSuffix(".xwd", "image/x-windowdump");
|
||||
setSuffix(".xyz", "chemical/x-xyz");
|
||||
setSuffix(".z", "application/x-compress");
|
||||
setSuffix(".zip", "application/zip");
|
||||
}
|
||||
|
||||
void listDirectory(File dir, PrintStream ps) throws IOException
|
||||
{
|
||||
ps.println("<TITLE>Directory listing</TITLE><P>\n");
|
||||
ps.println("<A HREF=\"..\">Parent Directory</A><BR>\n");
|
||||
String[] list = dir.list();
|
||||
for (int i = 0; list != null && i < list.length; i++) {
|
||||
File f = new File(dir, list[i]);
|
||||
if (f.isDirectory()) {
|
||||
ps.println("<A HREF=\""+list[i]+"/\">"+list[i]+"/</A><BR>");
|
||||
} else {
|
||||
ps.println("<A HREF=\""+list[i]+"\">"+list[i]+"</A><BR");
|
||||
}
|
||||
}
|
||||
ps.println("<P><HR><BR><I>" + (new Date()) + "</I>");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface HttpConstants {
|
||||
/** 2XX: generally "OK" */
|
||||
public static final int HTTP_OK = 200;
|
||||
public static final int HTTP_CREATED = 201;
|
||||
public static final int HTTP_ACCEPTED = 202;
|
||||
public static final int HTTP_NOT_AUTHORITATIVE = 203;
|
||||
public static final int HTTP_NO_CONTENT = 204;
|
||||
public static final int HTTP_RESET = 205;
|
||||
public static final int HTTP_PARTIAL = 206;
|
||||
|
||||
/** 3XX: relocation/redirect */
|
||||
public static final int HTTP_MULT_CHOICE = 300;
|
||||
public static final int HTTP_MOVED_PERM = 301;
|
||||
public static final int HTTP_MOVED_TEMP = 302;
|
||||
public static final int HTTP_SEE_OTHER = 303;
|
||||
public static final int HTTP_NOT_MODIFIED = 304;
|
||||
public static final int HTTP_USE_PROXY = 305;
|
||||
|
||||
/** 4XX: client error */
|
||||
public static final int HTTP_BAD_REQUEST = 400;
|
||||
public static final int HTTP_UNAUTHORIZED = 401;
|
||||
public static final int HTTP_PAYMENT_REQUIRED = 402;
|
||||
public static final int HTTP_FORBIDDEN = 403;
|
||||
public static final int HTTP_NOT_FOUND = 404;
|
||||
public static final int HTTP_BAD_METHOD = 405;
|
||||
public static final int HTTP_NOT_ACCEPTABLE = 406;
|
||||
public static final int HTTP_PROXY_AUTH = 407;
|
||||
public static final int HTTP_CLIENT_TIMEOUT = 408;
|
||||
public static final int HTTP_CONFLICT = 409;
|
||||
public static final int HTTP_GONE = 410;
|
||||
public static final int HTTP_LENGTH_REQUIRED = 411;
|
||||
public static final int HTTP_PRECON_FAILED = 412;
|
||||
public static final int HTTP_ENTITY_TOO_LARGE = 413;
|
||||
public static final int HTTP_REQ_TOO_LONG = 414;
|
||||
public static final int HTTP_UNSUPPORTED_TYPE = 415;
|
||||
|
||||
/** 5XX: server error */
|
||||
public static final int HTTP_SERVER_ERROR = 500;
|
||||
public static final int HTTP_INTERNAL_ERROR = 501;
|
||||
public static final int HTTP_BAD_GATEWAY = 502;
|
||||
public static final int HTTP_UNAVAILABLE = 503;
|
||||
public static final int HTTP_GATEWAY_TIMEOUT = 504;
|
||||
public static final int HTTP_VERSION = 505;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,18 +11,22 @@ import processing.app.EditorToolbar;
|
||||
|
||||
public class JavaScriptToolbar extends EditorToolbar {
|
||||
|
||||
// static protected final int RUN = 0;
|
||||
// static protected final int STOP = 1;
|
||||
static protected final int RUN = 0;
|
||||
static protected final int STOP = 1;
|
||||
|
||||
static protected final int NEW = 0;
|
||||
static protected final int OPEN = 1;
|
||||
static protected final int SAVE = 2;
|
||||
static protected final int EXPORT = 3;
|
||||
static protected final int NEW = 2;
|
||||
static protected final int OPEN = 3;
|
||||
static protected final int SAVE = 4;
|
||||
static protected final int EXPORT = 5;
|
||||
|
||||
|
||||
static public String getTitle(int index, boolean shift) {
|
||||
switch (index) {
|
||||
case NEW: return !shift ? "New" : "New Editor Window";
|
||||
static public String getTitle ( int index, boolean shift )
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case RUN: return "Start server";
|
||||
case STOP: return "Stop server";
|
||||
case NEW: return !shift ? "New" : "New Editor Window";
|
||||
case OPEN: return !shift ? "Open" : "Open in Another Window";
|
||||
case SAVE: return "Save";
|
||||
case EXPORT: return "Export for Web";
|
||||
@@ -31,24 +35,35 @@ public class JavaScriptToolbar extends EditorToolbar {
|
||||
}
|
||||
|
||||
|
||||
public JavaScriptToolbar(Editor editor, Base base) {
|
||||
public JavaScriptToolbar ( Editor editor, Base base )
|
||||
{
|
||||
super(editor, base);
|
||||
}
|
||||
|
||||
|
||||
public void init() {
|
||||
public void init ()
|
||||
{
|
||||
Image[][] images = loadImages();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
addButton(getTitle(i, false), getTitle(i, true), images[i], i == NEW);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
addButton( getTitle(i, false), getTitle(i, true), images[i], i == NEW );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void handlePressed(MouseEvent e, int index) {
|
||||
public void handlePressed ( MouseEvent e, int index )
|
||||
{
|
||||
boolean shift = e.isShiftDown();
|
||||
JavaScriptEditor jsEditor = (JavaScriptEditor) editor;
|
||||
|
||||
switch (index) {
|
||||
|
||||
case RUN:
|
||||
jsEditor.handleStartServer();
|
||||
break;
|
||||
|
||||
case STOP:
|
||||
jsEditor.handleStopServer();
|
||||
break;
|
||||
|
||||
case OPEN:
|
||||
JPopupMenu popup = editor.getMode().getToolbarMenu().getPopupMenu();
|
||||
@@ -68,7 +83,7 @@ public class JavaScriptToolbar extends EditorToolbar {
|
||||
break;
|
||||
|
||||
case EXPORT:
|
||||
jsEditor.handleExport();
|
||||
jsEditor.handleExport( true );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user