From dd927f62cd2ed5bfbe3e0fcb32dabc7bd8a34089 Mon Sep 17 00:00:00 2001 From: fjenett Date: Fri, 23 Mar 2012 18:23:32 +0000 Subject: [PATCH] Fix for issues #936 and #848 --- .../mode/javascript/BasicServer.java | 992 ++++++++++-------- .../mode/javascript/JavaScriptBuild.java | 182 +++- .../mode/javascript/JavaScriptEditor.java | 12 +- .../mode/javascript/JavaScriptMode.java | 47 +- .../mode/javascript/ServingEditor.java | 54 +- .../{applet_js => template}/processing.js | 0 javascript/todo.txt | 4 + 7 files changed, 767 insertions(+), 524 deletions(-) rename javascript/{applet_js => template}/processing.js (100%) diff --git a/app/src/processing/mode/javascript/BasicServer.java b/app/src/processing/mode/javascript/BasicServer.java index 6081500d3..35e0a74df 100644 --- a/app/src/processing/mode/javascript/BasicServer.java +++ b/app/src/processing/mode/javascript/BasicServer.java @@ -11,7 +11,8 @@ import java.util.*; */ class BasicServer implements HttpConstants, Runnable { - + ArrayList listeners; + // TODO how to handle too many servers? // TODO read settings from sketch.properties // NOTE 0.0.0.0 does not work on XP @@ -20,22 +21,23 @@ class BasicServer implements HttpConstants, Runnable Thread thread = null; ServerSocket server = null; - //private ArrayList threads = new ArrayList(); - //private int workers = 5; + //private ArrayList threads = new ArrayList(); + //private int workers = 5; - private File virtualRoot; - private int timeout = 5000; + private File virtualRoot; + private int timeout = 5000; private int port = -1; private boolean running = false, inited = false; // private boolean stopping = false; + private ArrayList addresses; + BasicServer ( File root ) { - if ( virtualRoot == null && root.exists() && root.canRead() ) - { - virtualRoot = root; - } + setRoot( root ); + + findPort(); } public File getRoot () @@ -45,7 +47,22 @@ class BasicServer implements HttpConstants, Runnable public void setRoot ( File root ) { - virtualRoot = root; + if ( root.exists() && root.isDirectory() && root.canRead() ) + { + virtualRoot = root; + } + else + { + System.err.println( "BasicServer: error setting " ); + } + } + + public void addListener ( BasicServerListener l ) + { + if ( listeners == null ) listeners = new ArrayList(); + if ( l != null ) { + listeners.add( l ); + } } public int getTimeout () @@ -58,6 +75,50 @@ class BasicServer implements HttpConstants, Runnable return localDomain + ":" + getPort() + "/"; } + public ArrayList getInetAddresses () + { + addresses = new ArrayList(); + + try { + NetworkInterface ni = NetworkInterface.getByInetAddress( InetAddress.getLocalHost() ); + Enumeration ia = ni.getInetAddresses(); + while ( ia.hasMoreElements () ) + { + InetAddress elem = ia.nextElement(); + if ( elem instanceof Inet6Address ) + { + // ? + continue; + } + else + { + addresses.add( elem.getHostAddress() ); + } + } + } catch ( Exception e ) { + // ignore? + } + + return addresses; + } + + private void findPort () + { + ServerSocket ss = null; + try { + + ss = new ServerSocket( 0 ); + ss.setReuseAddress(true); + port = ss.getLocalPort(); + ss.close(); + + } catch ( IOException ioe ) { + System.err.println(ioe); + } catch ( SecurityException se ) { + System.err.println(se); + } + } + public int getPort () { return port; @@ -65,31 +126,39 @@ class BasicServer implements HttpConstants, Runnable public void setPort ( int newPort ) { - if ( !isRunning() ) { - port = newPort; + if ( !isRunning() ) + { + // port available? see: + // http://stackoverflow.com/questions/434718/sockets-discover-port-availability-using-java + // http://stackoverflow.com/questions/2675362/how-to-find-an-available-port + + if ( port >= 0 ) + { + if ( !available(port) ) + { + System.err.println( "BasicServer: " + + "that port ("+port+") seems to be taken " + + "or is out of range (<1025 or >49151)"); + System.out.println( "... if it works anyway, ignore the warning." ); + } + else + { + port = newPort; + } + } } } public void start () { - // TODO check port available? - // see: - // http://stackoverflow.com/questions/434718/sockets-discover-port-availability-using-java - // http://stackoverflow.com/questions/2675362/how-to-find-an-available-port - - if ( port >= 0 ) + if ( virtualRoot == null ) { - if ( !available(port) ) - { - System.err.println( "BasicServer: " + - "that port ("+port+") seems to be taken " + - "or is out of range (0-65535)"); - port = -1; - } + System.err.println( "BasicServer: virtual root is null." ); + return; } thread = null; - thread = new Thread(this, "ProcessingJSServer"); + thread = new Thread( this, "Processing.BasicServer" ); thread.start(); } @@ -98,55 +167,57 @@ class BasicServer implements HttpConstants, Runnable * http://mina.apache.org/ * http://stackoverflow.com/questions/434718/sockets-discover-port-availability-using-java */ - public static boolean available (int port) + public static boolean available ( int port ) { // http://en.wikipedia.org/wiki/Port_number // http://en.wikipedia.org/wiki/Ephemeral_port - if (port < 0 || port > 65535) + if ( port < 1025 || port > 49151 ) { - //throw new IllegalArgumentException( "Invalid start port: " + port ); + //throw new IllegalArgumentException( "Invalid start port: " + port ); return false; - } + } - ServerSocket ss = null; - DatagramSocket ds = null; - try { - ss = new ServerSocket(port); - ss.setReuseAddress(true); - ds = new DatagramSocket(port); - ds.setReuseAddress(true); - return true; - } catch (IOException e) { + ServerSocket servSocket = null; + DatagramSocket dataSock = null; + try { + servSocket = new ServerSocket(port); + servSocket.setReuseAddress(true); + servSocket.close(); + dataSock = new DatagramSocket(port); + dataSock.setReuseAddress(true); + dataSock.close(); + return true; + } catch (IOException e) { e.printStackTrace(); - } finally { - if (ds != null) { - ds.close(); - } + } finally { + if (dataSock != null) { + dataSock.close(); + } - if (ss != null) { - try { - ss.close(); - } catch (IOException e) { - /* should not be thrown */ - } - } - } + if (servSocket != null) { + try { + servSocket.close(); + } catch (IOException e) { + /* should not be thrown */ + } + } + } - return false; + return false; } public void restart () { - if ( running ) - shutDown(); + if ( running ) shutDown(); start(); } // http://bit.ly/eA8iGj public void shutDown () - { + { + //System.out.println("Shutting down"); /*if ( threads != null ) { for ( Worker w : threads ) @@ -164,6 +235,14 @@ class BasicServer implements HttpConstants, Runnable } catch ( Exception e ) { e.printStackTrace(); } + + if ( listeners != null ) + { + for ( BasicServerListener l : listeners ) + { + l.serverStopped(); + } + } } public boolean isRunning () @@ -171,28 +250,21 @@ class BasicServer implements HttpConstants, Runnable return running && inited; } - public void run () - { - if ( virtualRoot == null ) - { - System.err.println( "ProcessingJSServer: virtual root is null." ); - return; - } - + public void run () + { try { running = true; if ( port < 0 ) { - server = new ServerSocket( 0 ); + server = new ServerSocket( 0 ); port = server.getLocalPort(); /* self assigned free port */ } else { - server = new ServerSocket( port ); - //System.out.println( server.getLocalPort() ); + server = new ServerSocket( port ); } } catch ( IOException ioe ) { @@ -202,20 +274,29 @@ class BasicServer implements HttpConstants, Runnable System.err.println(se); } - try { + try + { if ( server != null ) { inited = true; - while ( thread != null ) + if ( listeners != null ) + { + for ( BasicServerListener l : listeners ) + { + l.serverStarted(); + } + } + + while ( thread != null ) { Socket s = server.accept(); - Worker ws = new Worker( virtualRoot ); - ws.setSocket(s); - //threads.add(ws); - (new Thread(ws, "ProcessingJSServer Worker")).start(); - } + Worker ws = new Worker( virtualRoot ); + ws.setSocket(s); + //threads.add(ws); + (new Thread(ws, "Processing.BasicServer.Worker")).start(); + } } else { @@ -223,40 +304,39 @@ class BasicServer implements HttpConstants, Runnable } } catch ( IOException ioe ) { // happens on shutDown(), ignore .. - //System.err.println(ioe); + //System.err.println( ioe ); } running = false; - } + } } - class Worker extends BasicServer implements HttpConstants, Runnable { - final static int BUF_SIZE = 2048; + final static int BUF_SIZE = 2048; - static final byte[] EOL = {(byte)'\r', (byte)'\n' }; + static final byte[] EOL = {(byte)'\r', (byte)'\n' }; - /* buffer to use for requests */ - byte[] buf; - /* Socket to client we're handling */ - private Socket s; + /* buffer to use for requests */ + byte[] buf; + /* Socket to client we're handling */ + private Socket socket; private boolean stopping = false; - Worker ( File root ) + Worker ( File root ) { super( root ); - buf = new byte[BUF_SIZE]; - s = null; - } + buf = new byte[BUF_SIZE]; + socket = null; + } - synchronized void setSocket( Socket s ) + synchronized void setSocket( Socket s ) { - this.s = s; - notify(); - } + socket = s; + notify(); + } synchronized void stop () { @@ -264,116 +344,120 @@ implements HttpConstants, Runnable notify(); } - public synchronized void run () + public synchronized void run () { - while ( true && !stopping ) + while ( true && !stopping ) { - if (s == null) + if ( socket == null ) { - /* nothing to do */ - try { - wait(); - } catch (InterruptedException e) { - /* should not happen */ - continue; - } - } - if ( s != null && !stopping ) - { - try { - handleClient(); - } catch (Exception e) { - e.printStackTrace(); - } + /* nothing to do */ + try { + wait(); + } catch (InterruptedException e) { + /* should not happen */ + continue; + } } - s = null; - return; - } - } + if ( socket != null && !stopping ) + { + try { + handleClient(); + } catch (Exception e) { + e.printStackTrace(); + } + } + socket = 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; + void handleClient() throws IOException + { + InputStream is = new BufferedInputStream( socket.getInputStream() ); + PrintStream ps = new PrintStream( socket.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. + */ + socket.setSoTimeout( getTimeout() ); + socket.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, index, i-index)). - replace('/', File.separatorChar); - if (fname.startsWith(File.separator)) + while (nread < BUF_SIZE) { - fname = fname.substring(1); - } + 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(); + socket.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, index, i-index)). + replace('/', File.separatorChar); + if (fname.startsWith(File.separator)) + { + fname = fname.substring(1); + } fname = java.net.URLDecoder.decode(fname, "UTF-8"); @@ -387,147 +471,164 @@ outerloop: } else { - File targ = new File( getRoot(), fname ); - if (targ.isDirectory()) + File targ = new File( getRoot(), fname ); + if (targ.isDirectory()) { - File ind = new File(targ, "index.html"); - if (ind.exists()) { - targ = ind; - } - } + File ind = new File(targ, "index.html"); + if (ind.exists()) { + targ = ind; + } + } - boolean OK = printHeaders(targ, ps); - if (doingGet) + boolean OK = printHeaders(targ, ps); + if (doingGet) { - if (OK) { - sendFile(targ, ps); - } else { - send404(targ, ps); - } - } + if (OK) { + sendFile(targ, ps); + } else { + send404(targ, ps); + } + } } - } finally { - s.close(); - } - } + } finally { + socket.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; - } + boolean printHeaders ( File targ, PrintStream ps ) throws IOException + { + boolean ret = false; - 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"); - } + if (!targ.exists()) + { + ps.print("HTTP/1.0 " + HTTP_NOT_FOUND + " not found"); + ps.write(EOL); + ret = false; + } else { + ps.print("HTTP/1.0 " + HTTP_OK + " OK"); + ps.write(EOL); + ret = true; + } + // System.out.println(String.format( + // "From %s: GET %s --> %s", + // socket.getInetAddress().getHostAddress(), + // targ.getAbsolutePath(), + // (ret ? "200" : "404") + // )); + + ps.print("Server: Processing/2.0"); + ps.write(EOL); + ps.print("Date: " + (new Date())); + ps.write(EOL); + + // ps.print("Access-Control-Allow-Origin: *"); + // ps.write(EOL); + // ps.print("Access-Control-Request-Method: *"); + // 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 logAndSendNop (PrintStream ps) throws IOException { - ps.write(EOL); - ps.write(EOL); - ps.println("\n"); - } + 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()); - } + void logAndSendNop (PrintStream ps) throws IOException + { + ps.write(EOL); + ps.write(EOL); + ps.println("\n"); + } - try { - int n; - while ((n = is.read(buf)) > 0) { - ps.write(buf, 0, n); - } - } finally { - is.close(); - } - } + 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()); + } - /* mapping of file extensions to content-types */ - static java.util.Hashtable map = new java.util.Hashtable(); + try { + int n; + while ((n = is.read(buf)) > 0) { + ps.write(buf, 0, n); + } + } finally { + is.close(); + } + } - static { - fillMap(); - } + /* mapping of file extensions to content-types */ + static java.util.Hashtable map = new java.util.Hashtable(); - static void setSuffix(String k, String v) { - map.put(k, v); - } + static { + fillMap(); + } - static void 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("", "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(".asc", "text/plain"); setSuffix(".asd", "application/astound"); setSuffix(".asn", "application/astound"); - setSuffix(".atom", "application/atom+xml"); - setSuffix(".au", "audio/basic"); + setSuffix(".atom", "application/atom+xml"); + setSuffix(".au", "audio/basic"); setSuffix(".avi", "video/x-msvideo"); - 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(".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(".cgm", "image/cgm"); setSuffix(".chm", "application/mshelp"); setSuffix(".cht", "audio/x-dspeeh"); setSuffix(".class", "application/octet-stream"); @@ -535,23 +636,23 @@ outerloop: setSuffix(".coffee", "text/coffeescript"); setSuffix(".com", "application/octet-stream"); setSuffix(".cpio", "application/x-cpio"); - setSuffix(".cpt", "application/mac-compactpro"); + 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(".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(".dmg", "application/octet-stream"); + setSuffix(".dms", "application/octet-stream"); setSuffix(".doc", "application/msword"); setSuffix(".dot", "application/msword"); - setSuffix(".dtd", "application/xml-dtd"); + setSuffix(".dtd", "application/xml-dtd"); setSuffix(".dus", "audio/x-dspeeh"); - setSuffix(".dv", "video/x-dv"); + setSuffix(".dv", "video/x-dv"); setSuffix(".dvi", "application/x-dvi"); setSuffix(".dwf", "drawing/x-dwf"); setSuffix(".dwg", "application/acad"); @@ -560,137 +661,137 @@ outerloop: setSuffix(".eps", "application/pdf"); setSuffix(".es", "audio/echospeech"); setSuffix(".etx", "text/x-setext"); - 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(".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(".gram", "application/srgs"); setSuffix(".grxml", "application/srgs+xml"); setSuffix(".gtar", "application/x-gtar"); - setSuffix(".gtar", "application/x-gtar"); + setSuffix(".gtar", "application/x-gtar"); setSuffix(".gz", "application/gzip"); - setSuffix(".h", "text/plain"); + 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(".ice", "x-conference/x-cooltalk"); setSuffix(".ico", "image/x-icon"); - setSuffix(".ics", "text/calendar"); + setSuffix(".ics", "text/calendar"); setSuffix(".ief", "image/ief"); - setSuffix(".ifb", "text/calendar"); - setSuffix(".iges", "model/iges"); - setSuffix(".igs", "model/iges"); + 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(".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(".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/m4v"); - setSuffix(".mac", "image/x-macpaint"); + 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/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(".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(".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(".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(".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(".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(".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(".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(".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(".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(".qti", "image/x-quicktime"); + setSuffix(".qtif", "image/x-quicktime"); setSuffix(".ra", "audio/x-pn-realaudio"); - 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(".rdf", "application/rdf+xml"); setSuffix(".rgb", "image/x-rgb"); - setSuffix(".rm", "application/vnd.rn-realmedia"); + 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(".rtf", "text/rtf"); setSuffix(".rtx", "text/richtext"); setSuffix(".sca", "application/x-supercard"); - setSuffix(".sgm", "text/sgml"); - setSuffix(".sgml", "text/sgml"); + setSuffix(".sgm", "text/sgml"); + setSuffix(".sgml", "text/sgml"); setSuffix(".sh", "application/x-sh"); - setSuffix(".shar", "application/x-shar"); + setSuffix(".shar", "application/x-shar"); setSuffix(".shtml", "text/html"); - setSuffix(".silo", "model/mesh"); + 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(".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(".so", "application/octet-stream"); setSuffix(".spc", "text/x-speech"); setSuffix(".spl", "application/futuresplash"); setSuffix(".spr", "application/x-sprite"); @@ -699,9 +800,9 @@ outerloop: setSuffix(".stream", "audio/x-qt-stream"); setSuffix(".sv4cpio", "application/x-sv4cpio"); setSuffix(".sv4crc", "application/x-sv4crc"); - setSuffix(".svg", "image/svg+xml"); + setSuffix(".svg", "image/svg+xml"); setSuffix(".swf", "application/x-shockwave-flash"); - setSuffix(".t", "application/x-troff"); + setSuffix(".t", "application/x-troff"); setSuffix(".talk", "text/x-speech"); setSuffix(".tar", "application/x-tar"); setSuffix(".tbk", "application/toolbook"); @@ -717,22 +818,22 @@ outerloop: setSuffix(".tsi", "audio/tsplayer"); setSuffix(".tsp", "application/dsptype"); setSuffix(".tsv", "text/tab-separated-values"); - 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(".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(".vrml", "model/vrml"); setSuffix(".vts", "workbook/formulaone"); setSuffix(".vtts", "workbook/formulaone"); - setSuffix(".vxml", "application/voicexml+xml"); + setSuffix(".vxml", "application/voicexml+xml"); setSuffix(".wav", "audio/x-wav"); - setSuffix(".wav", "audio/x-wav"); + setSuffix(".wav", "audio/x-wav"); setSuffix(".wbmp", "image/vnd.wap.wbmp"); setSuffix(".wbmxl", "application/vnd.wap.wbxml"); setSuffix(".webm", "video/webm"); @@ -742,83 +843,86 @@ outerloop: setSuffix(".wmlsc", "application/vnd.wap.wmlscriptc"); setSuffix(".wrl", "model/vrml"); setSuffix(".xbm", "image/x-xbitmap"); - setSuffix(".xht", "application/xhtml+xml"); + 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(".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(".xyz", "chemical/x-xyz"); + setSuffix(".z", "application/x-compress"); setSuffix(".zip", "application/zip"); - } + } - void listDirectory(File dir, PrintStream ps) throws IOException - { - ps.println("Directory listing

\n"); - ps.println("Parent Directory
\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(""+list[i]+"/
"); - } else { - ps.println(""+list[i]+"



" + (new Date()) + ""); - } + void listDirectory ( File dir, PrintStream ps ) throws IOException + { + ps.println("Directory listing

\n"); + ps.println("Parent Directory
\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(""+list[i]+"/
"); + } else { + ps.println(""+list[i]+"



" + (new Date()) + ""); + } } 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; + /** 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; + /** 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; + /** 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; + /** 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; } - - +interface BasicServerListener +{ + public abstract void serverStarted(); + public abstract void serverStopped(); +} \ No newline at end of file diff --git a/app/src/processing/mode/javascript/JavaScriptBuild.java b/app/src/processing/mode/javascript/JavaScriptBuild.java index b4ed512f5..5c5ce5f8e 100644 --- a/app/src/processing/mode/javascript/JavaScriptBuild.java +++ b/app/src/processing/mode/javascript/JavaScriptBuild.java @@ -10,12 +10,16 @@ import java.io.FileWriter; import java.util.HashMap; import java.util.Map; import java.util.ArrayList; +import java.util.Enumeration; + +import java.net.*; import processing.app.Base; import processing.app.Mode; import processing.app.Sketch; import processing.app.SketchCode; import processing.app.SketchException; +import processing.app.Library; import processing.core.PApplet; @@ -24,9 +28,12 @@ import processing.mode.java.preproc.PdePreprocessor; 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_FOLDER_NAME = "template"; + public final static String EXPORTED_FOLDER_NAME = "web-export"; public final static String TEMPLATE_FILE_NAME = "template.html"; + + public final static String IMPORT_REGEX = + "^[\\s]*import[\\s]+([^\\s]+)[\\s]*"; /** * Answers with the first java doc style comment in the string, @@ -136,6 +143,11 @@ public class JavaScriptBuild sketch.ensureExistence(); this.binFolder = bin; + + // we need these .. + JavaScriptMode jsMode = (JavaScriptMode)mode; + JavaScriptEditor jsEditor = (JavaScriptEditor)jsMode.getEditor(); + BasicServer jsServer = jsEditor.getServer(); if ( bin.exists() ) { @@ -146,7 +158,7 @@ public class JavaScriptBuild // .. exceptions bubble up. preprocess(bin); - // move the data files, copies contents of sketch/data/ to applet_js/ + // move the data files, copies contents of sketch/data/ to web-export/ if (sketch.hasDataFolder()) { try { @@ -155,7 +167,7 @@ public class JavaScriptBuild } 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 " + - "the applet_js/ folder. Processing.js doesn't look for a data " + + "the web-export/ folder. Processing.js doesn't look for a data " + "folder, so lump them together."; Base.showWarning("Problem building the sketch", msg, e); } @@ -187,18 +199,17 @@ public class JavaScriptBuild 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); + // get width and height + int wide = PApplet.DEFAULT_WIDTH; + int high = PApplet.DEFAULT_HEIGHT; + String[] matches = PApplet.match(scrubbed, JavaBuild.SIZE_REGEX); if (matches != null) { try @@ -223,6 +234,81 @@ public class JavaScriptBuild } } // else no size() command found, defaults will be used + // try resolve imports + ArrayList importPackages = new ArrayList(); + String[] lines = scrubbed.split( "\n" ); + for ( String l : lines ) + { + int iIndex = l.indexOf( "import" ); + if ( iIndex != -1 ) + { + String[] iStatements = l.split(";"); + for ( String iExpression : iStatements ) + { + matches = PApplet.match( iExpression, JavaScriptBuild.IMPORT_REGEX ); + if ( matches != null && matches.length >= 2 && matches[1] != null ) + { + String iPackage = matches[1]; + iPackage = iPackage.trim(); + + if ( iPackage.indexOf(".*") != -1 ) { + // de.bezier.tutto.* + iPackage = iPackage.replace( ".*", "" ); + } else { + // de.bezier.uno.SingleClass + iPackage = iPackage.replaceAll( "\\.[^.]+$", "" ); + } + if ( !importPackages.contains(iPackage) ) // is this a "==" or ".equals()" ? + importPackages.add( iPackage ); + } + } + } + } + ArrayList jsImports = new ArrayList(); + if ( importPackages.size() > 0 ) + { + File libsExport = new File( bin, "libs" ); + if ( !libsExport.mkdir() ) + { + Base.showWarning( "Error", + "Unable to create 'libs' in export folder.", + null ); + return false; + } + } + for ( String pack : importPackages ) + { + Library lib = mode.getLibrary( pack ); + if ( lib != null ) + { + String libPath = lib.getJarPath(); + File libJar = new File( libPath ); + if ( libJar.exists() ) + { + File libJS = new File( libJar.getParent(), libJar.getName().replace(".jar",".js") ); + //System.out.println( libJS.getPath() ); + if ( libJS.exists() ) + { + String libJSDest = "libs" + File.separator + libJS.getName(); + File libJSDestFile = new File( bin, libJSDest ); + if ( libJSDestFile.exists() ) + { + System.out.println( "Duplicate import!" ); + } + try + { + Base.copyFile( libJS, + libJSDestFile ); + jsImports.add( libJSDest ); + + } catch ( Exception se ) { + se.printStackTrace(); + } + } + } + } + } + // final prep and write to template. // getTemplateFile() is very important as it looks and preps // any custom templates present in the sketch folder. @@ -237,10 +323,30 @@ public class JavaScriptBuild // generate an ID for the sketch to use with String sketchID = sketch.getName().replaceAll("[^a-zA-Z0-9]+", "").replaceAll("^[^a-zA-Z]+",""); + // add a handy method to read the generated sketchID - String scriptFiles = "\n"; + String scriptFiles = "\n"; + + // add imports if any ... + for ( String importScript : jsImports ) + { + scriptFiles += ""; + } // main .pde file first String sourceFiles = "" + @@ -271,31 +377,37 @@ public class JavaScriptBuild return false; } - // finally, add Processing.js - try + // finally, add files processing.js + String[] defaultJSFiles = new String[]{ + "processing.js" /*, "qrcode.js"*/ + }; + for ( String defaultJSFile : defaultJSFiles ) { - Base.copyFile( sketch.getMode().getContentFile( - EXPORTED_FOLDER_NAME+"/processing.js" - ), - new File( bin, "processing.js") - ); + try + { + Base.copyFile( sketch.getMode().getContentFile( + TEMPLATE_FOLDER_NAME + File.separator + defaultJSFile + ), + new File( bin, defaultJSFile ) + ); - } catch (IOException ioe) { - final String msg = "There was a problem copying processing.js to the " + - "build folder. You will have to manually add " + - "processing.js to the build folder before the sketch " + - "will run."; - Base.showWarning("There was a problem writing to the build folder", msg, ioe); - //return false; - } + } catch (IOException ioe) { + final String msg = "There was a problem copying " +defaultJSFile+ " to the " + + "build folder. You will have to manually add " + + defaultJSFile +" to the build folder before the sketch " + + "will run."; + Base.showWarning( "There was a problem writing to the build folder", msg, ioe); + //return false; + } + } 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 + * templates that might be living in the sketch folder. If such a "template" + * folder exists then it's contents will be copied over to "web-export" and * it's template.html will be used as template. */ private File getTemplateFile () @@ -309,7 +421,7 @@ public class JavaScriptBuild File appletJsFolder = new File( sketchFolder, EXPORTED_FOLDER_NAME ); try { - //TODO: this is potentially dangerous as it might override files in applet_js + //TODO: this is potentially dangerous as it might override files in "web-export" Base.copyDir( customTemplateFolder, appletJsFolder ); if ( !(new File( appletJsFolder, TEMPLATE_FILE_NAME )).delete() ) { @@ -320,13 +432,13 @@ public class JavaScriptBuild 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 + TEMPLATE_FOLDER_NAME + File.separator + TEMPLATE_FILE_NAME ); } } else return sketch.getMode().getContentFile( - EXPORTED_FOLDER_NAME + File.separator + TEMPLATE_FILE_NAME + TEMPLATE_FOLDER_NAME + File.separator + TEMPLATE_FILE_NAME ); } @@ -516,12 +628,12 @@ public class JavaScriptBuild /** - * Export the sketch to the default applet_js folder. + * Export the sketch to the default "web-export" folder. * @return success of the operation */ public boolean export() throws IOException, SketchException { - File applet_js = new File(sketch.getFolder(), EXPORTED_FOLDER_NAME); - return build( applet_js ); + File webExport = new File(sketch.getFolder(), EXPORTED_FOLDER_NAME); + return build( webExport ); } } diff --git a/app/src/processing/mode/javascript/JavaScriptEditor.java b/app/src/processing/mode/javascript/JavaScriptEditor.java index 92bb2aeee..554fa5fc6 100644 --- a/app/src/processing/mode/javascript/JavaScriptEditor.java +++ b/app/src/processing/mode/javascript/JavaScriptEditor.java @@ -298,7 +298,7 @@ public class JavaScriptEditor extends ServingEditor Sketch sketch = getSketch(); File ajs = sketch.getMode(). - getContentFile(JavaScriptBuild.EXPORTED_FOLDER_NAME); + getContentFile( JavaScriptBuild.TEMPLATE_FOLDER_NAME ); File tjs = getCustomTemplateFolder(); @@ -385,13 +385,13 @@ public class JavaScriptEditor extends ServingEditor * export to folder, start server, open in default browser. */ public void handleStartServer () - { + { statusEmpty(); - - if ( !handleExport( false ) ) return; - + startServer( getExportFolder() ); - + + if ( !handleExport( false ) ) return; + toolbar.activate(JavaScriptToolbar.RUN); } diff --git a/app/src/processing/mode/javascript/JavaScriptMode.java b/app/src/processing/mode/javascript/JavaScriptMode.java index 0f3f5ae49..48b9adef5 100644 --- a/app/src/processing/mode/javascript/JavaScriptMode.java +++ b/app/src/processing/mode/javascript/JavaScriptMode.java @@ -26,24 +26,29 @@ public class JavaScriptMode extends Mode private JavaScriptEditor jsEditor; - // create a new editor with the mode - public Editor createEditor( Base base, String path, EditorState state ) - { - jsEditor = new JavaScriptEditor( base, path, state, this ); - return jsEditor; - } + // create a new editor with the mode + public Editor createEditor( Base base, String path, EditorState state ) + { + jsEditor = new JavaScriptEditor( base, path, state, this ); - public JavaScriptMode( Base base, File folder ) - { - super(base, folder); - - try { - loadKeywords(); - } catch (IOException e) { - Base.showError("Problem loading keywords", - "Could not load keywords.txt, please re-install Processing.", e); - } - } + return jsEditor; + } + + public Editor getEditor() { + return jsEditor; + } + + public JavaScriptMode( Base base, File folder ) + { + super(base, folder); + + try { + loadKeywords(); + } catch (IOException e) { + Base.showError("Problem loading keywords", + "Could not load keywords.txt, please re-install Processing.", e); + } + } protected void loadKeywords() throws IOException { @@ -139,17 +144,17 @@ public class JavaScriptMode extends Mode } // all file extensions it supports - public String[] getExtensions() + public String[] getExtensions () { return new String[] {"pde", "js"}; } - public String[] getIgnorable() + public String[] getIgnorable () { return new String[] { "applet", - "applet_js", - "template_js" + "applet_js", + JavaScriptBuild.EXPORTED_FOLDER_NAME }; } diff --git a/app/src/processing/mode/javascript/ServingEditor.java b/app/src/processing/mode/javascript/ServingEditor.java index 6280739c7..a97ffff64 100644 --- a/app/src/processing/mode/javascript/ServingEditor.java +++ b/app/src/processing/mode/javascript/ServingEditor.java @@ -11,7 +11,7 @@ import java.io.File; import java.io.IOException; import javax.swing.JOptionPane; -public abstract class ServingEditor extends Editor +public abstract class ServingEditor extends Editor implements BasicServerListener { public final static String PROP_KEY_SERVER_PORT = "basicserver.port"; @@ -71,17 +71,22 @@ public abstract class ServingEditor extends Editor } } - protected int getServerPort () + public int getServerPort () { if ( server != null ) return server.getPort(); return -1; } - protected String getServerAddress () + public String getServerAddress () { if ( server != null && server.isRunning() ) return server.getAddress(); return null; } + + public BasicServer getServer () + { + return server; + } protected void startStopServer ( File root ) { @@ -98,8 +103,14 @@ public abstract class ServingEditor extends Editor protected BasicServer createServer ( File root ) { if ( server != null ) return server; + + if ( !root.exists() && !root.mkdir() ) + { + // bad .. let server handle the complaining .. + } server = new BasicServer( root ); + server.addListener( this ); File sketchProps = getSketchPropertiesFile(); if ( sketchProps.exists() ) { @@ -122,7 +133,7 @@ public abstract class ServingEditor extends Editor protected void startServer ( File root ) { if ( server != null && - (!server.isRunning() || !server.getRoot().equals(root)) ) + ( !server.isRunning() || !server.getRoot().equals(root) ) ) { // if server hung or something else went wrong .. stop it. server.shutDown(); @@ -131,20 +142,14 @@ public abstract class ServingEditor extends Editor if ( server == null ) { - server = createServer(root); + server = createServer( root ); + } + + if ( !server.isRunning() ) + { + server.setRoot( root ); server.start(); - - // a little delay to give the server time to kick in .. - long ts = System.currentTimeMillis(); - while ( System.currentTimeMillis() - ts < 200 ) {} - - while ( !server.isRunning() ) {} - - String location = server.getAddress(); - - statusNotice( "Server started: " + location ); - - openBrowserForServer(); + statusNotice( "Waiting for server to start ..." ); } else if ( server.isRunning() ) { @@ -164,7 +169,6 @@ public abstract class ServingEditor extends Editor if ( server != null && server.isRunning() ) server.shutDown(); - statusNotice("Server stopped."); } protected File getSketchPropertiesFile () @@ -190,4 +194,18 @@ public abstract class ServingEditor extends Editor Base.openURL( server.getAddress() ); } } + + // ---- interface BasicServerListener + + public void serverStarted () + { + String location = server.getAddress(); + statusNotice( "Server started: " + location ); + openBrowserForServer(); + } + + public void serverStopped () + { + statusNotice("Server stopped."); + } } \ No newline at end of file diff --git a/javascript/applet_js/processing.js b/javascript/template/processing.js similarity index 100% rename from javascript/applet_js/processing.js rename to javascript/template/processing.js diff --git a/javascript/todo.txt b/javascript/todo.txt index 23e4cd405..084d2fed0 100644 --- a/javascript/todo.txt +++ b/javascript/todo.txt @@ -41,4 +41,8 @@ A way to reopen the browser window, maybe even other browsers? Find your own IP address so you can test the sketch from other clients on the network. +---------------------------------------------------------------------------- + +Nice subpages for: 404, directory listing, ... + ---------------------------------------------------------------------------- \ No newline at end of file