Permalink
Browse files

Update the test page to automagickally provide bookmarklets on all in…

…terfaces. Added slime-js-browse-test funciton to slime-js.el to use the default browser to browse to the test page.
  • Loading branch information...
1 parent 38a11d4 commit 92887d7d6f1a859814739b4e72d504c4bff87f46 @jonnay jonnay committed Mar 27, 2012
Showing with 115 additions and 21 deletions.
  1. +1 −0 .gitignore
  2. +25 −1 client/test.html
  3. +31 −2 slime-js.el
  4. +58 −18 swank.js
View
1 .gitignore
@@ -0,0 +1 @@
+/node_modules/
View
26 client/test.html
@@ -1,8 +1,32 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
+ <title> Swank JS test page </title>
<meta http-equiv="X-UA-Compatible" content="IE=9">
<script type="text/javascript" src="/swank-js/swank-js-inject.js"></script>
</head>
- <body></body>
+ <body>
+ <h1> You have connected to swank.js! </h1>
+ <p> you can use ,select-remote to select this browser now! </h2>
+
+ <h2> Bookmarklets </h2>
+ <p> Here are some bookmarklets you can use to inject the swank
+ javascript on this page:</p>
+ <ul>
+ <!--[[bookmarklets]]-->
+ <li><a href="javascript:(function()%7BSwankJS.disconnect()%3B%7D)()%3B">swank
+ disconnect</a> </li>
+ </ul>
+
+ <h3> Adding a bookmarklet on iOS </h3>
+ <p> It's kind of a pain to do this. Thanks to <a href="http://static.chrisbray.com/bookmarklets/">Chris Bray</a> for
+ figuring this out! </p>
+ <ol>
+ <li> Add this page as a bookmark </li>
+ <li> Select and copy the bookmarklet text </li>
+ <li> Go to your bookmarks and tap edit the one you just made </li>
+ <li> Edit the name (if you like) and paste the URL.</li>
+ <li> Profit! </li>
+ </ol>
+ </body>
</html>
View
33 slime-js.el
@@ -44,7 +44,9 @@
(defcustom slime-js-swank-args '("run" "swank")
"Command arguments for running the swank-js server from node.js.
-Note that file paths need to be complete file paths, i.e. ~ to /home/you or /Uesrs/you."
+Note that file paths need to be complete file paths, i.e. ~ to /home/you or /Uesrs/you.
+If you are using npm, then you probably want this to have 2 values: \"run\" \"swank\".
+If you want swank-js to run on a differnet port, add it as the third element to this list."
:type '(repeat (string :tag "Arg"))
:group 'slime-js)
@@ -97,6 +99,11 @@ Note that file paths need to be complete file paths, i.e. ~ to /home/you or /Ues
(defvar slime-js-remote-history nil
"History list for JS remote names.")
+(defun slime-js-browse-test ()
+ "Interactive funciton to open the test page locally"
+ (interactive)
+ (browse-url "http://localhost:8009/client/test.html"))
+
(defun slime-js-read-remote-index (&optional prompt)
(let* ((completion-ignore-case nil)
(remotes (slime-eval '(js:list-remotes)))
@@ -110,7 +117,7 @@ Note that file paths need to be complete file paths, i.e. ~ to /home/you or /Ues
(p (or (position
(completing-read prompt (slime-bogus-completion-alist remote-names)
nil nil nil
- 'slime-remote-history nil)
+ 'slime-js-remote-history nil)
remote-names :test #'equal)
(error "bad remote name"))))
(first (elt remotes p))))
@@ -163,6 +170,8 @@ Note that file paths need to be complete file paths, i.e. ~ to /home/you or /Ues
(message "Reloading the page"))))
(defun slime-js-refresh-css ()
+ "If the current buffer points to a CSS file then the browser
+will reload it. Otherwise it will reload all linked stylesheets"
(interactive)
(slime-js-eval
(format "SwankJS.refreshCSS('%s')"
@@ -175,6 +184,26 @@ Note that file paths need to be complete file paths, i.e. ~ to /home/you or /Ues
#'(lambda (v)
(message "Refreshing CSS"))))
+(defun slime-js-make-js-string (string)
+ "escapes the string so that it can be used as a string in js"
+ (concat "\"" (replace-regexp-in-string "\n" "\\n" string nil t) "\""))
+
+(defun slime-js-buffer-or-region-string ()
+ (let ((start (if (region-active-p) (region-beginning) (point-min)))
+ (end (if (region-active-p) (region-end) (point-max))))
+ (buffer-substring-no-properties start end)))
+
+(defun slime-js-embed-css (&optional arg)
+ "send an active region or the whole buffer string to the browser
+and embed it in a style element"
+ (interactive "P")
+ (let ((command (if arg "removeEmbeddedCSS" "embedCSS"))
+ (param (if arg "" (slime-js-make-js-string
+ (slime-js-buffer-or-region-string)))))
+ (slime-js-eval
+ (format "SwankJS.%s(%s)" command param)
+ #'(lambda (v) (message "Embedding CSS")))))
+
(defun slime-js-start-of-toplevel-form ()
(interactive)
(when js2-mode-buffer-dirty-p
View
76 swank.js
@@ -1,3 +1,4 @@
+#!/usr/bin/env node
// -*- mode: js2 -*-
//
// Copyright (c) 2010 Ivan Shvedunov. All rights reserved.
@@ -43,17 +44,16 @@ var executive = new swh.Executive({ config: cfg });
var swankServer = net.createServer(
function (stream) {
- stream.setEncoding("utf-8");
var handler = new swh.Handler(executive);
var parser = new swp.SwankParser(
function onMessage (message) {
handler.receive(message);
});
handler.on(
"response", function (response) {
- var responseText = swp.buildMessage(response);
- console.log("response: %s", responseText);
- stream.write(responseText);
+ var responseBuf = swp.buildMessage(response);
+ console.log("response: %s", responseBuf.toString());
+ stream.write(responseBuf);
});
stream.on(
"data", function (data) {
@@ -165,14 +165,14 @@ HttpListener.prototype.clientVersion = "0.1";
HttpListener.prototype.cachedFiles = {};
HttpListener.prototype.clientFiles = {
- 'json2.js': 'json2.js',
- 'stacktrace.js': 'stacktrace.js',
- 'swank-js.js': 'swank-js.js',
- 'load.js': 'load.js',
- 'swank-js-inject.js': 'swank-js-inject.js',
- 'swank-completion.js': 'swank-completion.js',
- 'browser-tests.js': 'browser-tests.js',
- 'test.html': 'test.html'
+ 'json2.js': 'client/json2.js',
+ 'stacktrace.js': 'client/stacktrace.js',
+ 'swank-js.js': 'client/swank-js.js',
+ 'load.js': 'client/load.js',
+ 'swank-js-inject.js': 'client/swank-js-inject.js',
+ 'browser-tests.js': 'client/browser-tests.js',
+ 'test.html': 'client/test.html',
+ 'completion.js': 'completion.js'
};
HttpListener.prototype.types = {
@@ -346,13 +346,48 @@ HttpListener.prototype.doProxyRequest = function doProxyRequest (targetUrl, requ
});
};
+HttpListener.prototype.getBookMarklets = function getBookMarklets() {
+ //TBD: Allow IPv6 Bookmarklets?
+ var ifaces = require('os').networkInterfaces();
+ var ips = [];
+
+ //TBD: This sucks and can probably be done much better in a functional style
+ for (dev in ifaces) {
+ console.log ("found device "+dev);
+ ifaces[dev].forEach(function(details) {
+ console.log(details);
+ if (details.family=='IPv4') {
+ ips.push(details.address);
+ }
+ });
+ }
+
+ //console.log(ips);
+
+ //TODO: the port is a magic number. Needs to stop being magic.
+ var out = ips.map(function(ip){
+ var bookmarklet = escape("(function(d){window.swank_server='http://"+ip+":8009/';if(!d.getElementById('swank-js-inj')){var h=d.getElementsByTagName('head')[0],s=d.createElement('script');s.id='swank-js-inj';s.type='text/javascript';s.src=swank_server+'swank-js/swank-js-inject.js';h.appendChild(s);}})(document);");
+ return '<li><a href="javascript:'+bookmarklet +'"> Connet to slime on '+ip+'</a><br/>javascript:'+bookmarklet+'</li>';
+ });
+ //console.log(out.join('\n'));
+ return out.join('\n');
+}
+
HttpListener.prototype.sendCachedFile = function sendCachedFile (req, res, path) {
if (req.headers['if-none-match'] == this.clientVersion) {
res.writeHead(304);
res.end();
} else {
+ // sorry for this, but there is only one replacement, and only one file to replace, so
+ // for now... some bad code. But if there needs to be a new replacement, or replacements
+ // on more then one file, this'll need updating.
+ var out = ((path == 'client/test.html') ? (this.cachedFiles[path].content+'').replace('<!--[[bookmarklets]]-->',this.getBookMarklets())
+ : this.cachedFiles[path].content);
+ //console.log(out);
+ //TBD: Remove the setting of the length header earlier on in the process.
+ this.cachedFiles[path].headers['Content-Length'] = Buffer(out).length;
res.writeHead(200, this.cachedFiles[path].headers);
- res.end(this.cachedFiles[path].content, this.cachedFiles[path].encoding);
+ res.end(out, this.cachedFiles[path].encoding);
}
};
@@ -366,28 +401,33 @@ HttpListener.prototype.serveClient = function serveClient(req, res) {
var path = url.parse(req.url).pathname, parts, cn;
// console.log("%s %s", req.method, req.url);
if (path && path.indexOf("/swank-js/") != 0) {
- // console.log("--> proxy");
+ console.log("--> proxy");
this.proxyRequest(req, res);
return;
}
- var file = path.substr(1).split('/').slice(1);
+
+ console.log("--> internal");
+ var file = path.substr(1).split('/').slice(1);
var localPath = this.clientFiles[file];
- if (req.method == 'GET' && localPath !== undefined){
+ if (req.method == 'GET' && localPath !== undefined) {
// TBD: reenable caching, check datetime of the file
// if (path in this.cachedFiles){
// this.sendCachedFile(req, res, path);
// return;
// }
fs.readFile(
- __dirname + '/client/' + localPath, function(err, data) {
+ __dirname + '/' + localPath, function(err, data) {
if (err) {
console.log("error: %s", err);
self.notFound(res);
} else {
var ext = localPath.split('.').pop();
self.cachedFiles[localPath] = {
+ // right now there is no difference between cached files
+ // and files inside of the client dir. That should probably change
+ // soon.
headers: {
'Content-Length': data.length,
'Content-Type': self.types[ext],
@@ -458,4 +498,4 @@ io.sockets.on(
// TBD: handle/add X-Forwarded-For headers
// TBD: fix all assert calls: we need (actual, expected) not (expected, actual)
// TBD: invoke SwankJS.setup() only when DOM is ready (at least in IE)
-// TBD: timeouts for browser requests
+// TBD: timeouts for browser requests

0 comments on commit 92887d7

Please sign in to comment.