Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added support for Chrome. Extracted common functionality to jsreload.js.

  • Loading branch information...
commit c441d9f7ee9d689e602ee792eb26ca46997bf053 1 parent 485c493
@rauschma authored
View
25 README.md
@@ -1,12 +1,27 @@
# JSReload
-This project contains several scripts that help with automatically reloading a tab in Safari whenever a file changes:
+This project contains several scripts that help with automatically reloading a tab in a browser whenever a file changes:
-1. `tools/watchdir.js` watches all .html and .css files in a directory and reloads the first tab in the first window when one of them changes.
-2. `grunt.js` watches all .asc files in its directory. If one of them changes, it converts it to HTML via the `asciidoc` command and then reloads Safari.
+1. `tools/watchdir.js` watches all webdev files (.html, .css, .js) in a directory and reloads the first tab of the frontmost browser window when one of them changes.
+2. `tools/watchfile.js` opens a file in a web browser, watches it and reloads the first tab of the frontmost browser window if it changes.
+3. `grunt.js` is a Grunt build script. You put it inside a project directory. Its `watch` task is invoked as follows.
-Prerequisites:
+ grunt watch
+
+ This task watches all .asc files in the project directory. If one of them changes, it is converted to HTML via the `asciidoc` command. Afterwards, the first tab of the frontmost browser window is reloaded.
+All scripts depend on `node_modules/jsreload`. Safari is currently used by the scripts, but that can easily be changed to Chrome by replacing
+
+ jsreload.runReloadSafari(...);
+
+with
+
+ jsreload.runReloadChrome(...);
+
+## Requirements
+
+- Supported browsers: Safari, Chrome
+- Mac OS X (reloading a browser currently depends on AppleScript)
- Node.js
+ - Package: underscore (trivial to install via npm)
- [Grunt](http://gruntjs.com/) (only needed for option #2)
-- Mac OS X (reloading Safari is done via AppleScript)
View
139 node_modules/jsreload.js
@@ -0,0 +1,139 @@
+var spawn = require('child_process').spawn;
+var fs = require('fs');
+var path = require('path');
+var _ = require("underscore");
+
+var e = exports;
+
+//------------------- Watching the file system
+
+
+var filesToWatch = {
+ ".html": 1,
+ ".css": 1,
+ ".js": 1
+};
+e.watchDir = function (dir, action) {
+ fs.readdirSync(dir).forEach(function (filename) {
+ var absolute = path.resolve(dir, filename);
+
+ var stats = fs.statSync(absolute);
+ if (stats.isDirectory()) {
+ e.watchDir(absolute);
+ } else if (stats.isFile()) {
+ if (path.basename(absolute).indexOf(".") !== 0 && path.extname(absolute) in filesToWatch) {
+ console.log("WATCH: "+absolute);
+ e.watchFile(absolute, action);
+ }
+ }
+ });
+}
+
+/**
+ * @param mtime Optional
+ */
+e.watchFile = function (filename, action, mtime) {
+ if (mtime === undefined) {
+ mtime = fs.statSync(filename).mtime.getTime()
+ }
+
+ var watcher = fs.watch(filename);
+ var handler = handleFileChanges.bind(null, filename, mtime, watcher, action);
+
+ // Most editors trigger a series of events whenever a single file is saved
+ // Via debouncing, we only take action after the last event.
+ watcher.on("change", _.debounce(handler, 250));
+}
+
+function handleFileChanges(absName, mtime, watcher, action,
+ /* Listener parameters: */
+ event, fileName) {
+ // On Mac OS X, fileName is always null
+
+ switch (event) {
+ case 'rename':
+ // Some editors (vi) rename the file when swapping it with the new version
+ watcher.close();
+ if (fs.existsSync(absName)) {
+ mtime = fileChanged(event, absName, mtime, action);
+ e.watchFile(absName, action, mtime);
+ } else {
+ // Happens if a file is deleted or a program renames the file.
+ // The latter case is usually prevented by debouncing.
+ console.log("STOPPED WATCHING: "+absName);
+ }
+ break;
+ case 'change':
+ mtime = fileChanged(event, absName, mtime, action);
+ break;
+ }
+}
+
+function fileChanged(event, absName, oldMTime, action) {
+ // Check the date of last modification to make sure that there really was a change
+ var mtime = fs.statSync(absName).mtime.getTime();
+ if (mtime !== oldMTime) {
+ console.log(event.toUpperCase()+": "+absName);
+ action();
+ }
+ return mtime;
+}
+
+//------------------- Interacting with Mac OS X
+
+/**
+ * @param appName Optional
+ * @param arg A file name or a URL
+ */
+e.runOpen = function (appName, arg, callback) {
+ var osa = spawn("open", ["-a", appName, arg]);
+ var out = "";
+ var err = "";
+ osa.stdout.on('data', function (data) {
+ out += data;
+ });
+ osa.stderr.on('data', function (data) {
+ err += data;
+ });
+ osa.on('exit', function (code) {
+ callback();
+ });
+}
+
+/**
+ * @param callback Optional
+ */
+e.runAppleScript = function (script, callback) {
+ var osa = spawn("osascript", ["-e", script]);
+ var out = "";
+ var err = "";
+ osa.stdout.on('data', function (data) {
+ out += data;
+ });
+ osa.stderr.on('data', function (data) {
+ err += data;
+ });
+ osa.on('exit', function (code) {
+ // Ignore stdout (which shows the return value of the AppleScript code)
+ if (err.length > 0) {
+ console.log("STDERR: "+err);
+ }
+ if (callback) {
+ callback();
+ }
+ });
+}
+
+e.chromeAppName = "Google Chrome";
+e.runReloadChrome = e.runAppleScript.bind(null, '\
+tell application "'+e.chromeAppName+'"\n\
+ tell first tab of first window to reload\n\
+end tell\n\
+');
+e.safariAppName = "Safari";
+e.runReloadSafari = e.runAppleScript.bind(null, '\
+tell application "'+e.safariAppName+'"\n\
+ set mytab to first tab of first window\n\
+ tell mytab to do javascript "window.location.reload()"\n\
+end tell\n\
+');
View
9 tasks/reloadchrome.js
@@ -0,0 +1,9 @@
+module.exports = function(grunt) {
+
+ var jsreload = require('jsreload');
+
+ grunt.registerTask('reloadchrome', 'Reloads the first tab of the first window of Google Chrome', function() {
+ var taskDone = this.async();
+ jsreload.runReloadChrome(taskDone);
+ });
+};
View
35 tasks/reloadsafari.js
@@ -1,40 +1,9 @@
module.exports = function(grunt) {
- var spawn = require('child_process').spawn;
+ var jsreload = require('jsreload');
grunt.registerTask('reloadsafari', 'Reloads the first tab of the first window of Safari', function() {
var taskDone = this.async();
- reloadSafari(taskDone);
+ jsreload.runReloadSafari(taskDone);
});
-
- // Inspiration: http://brettterpstra.com/watch-for-file-changes-and-refresh-your-browser-automatically/
- var code = '\
- tell application "Safari"\n\
- set mytab to first tab of first window\n\
- tell mytab to do javascript "window.location.reload()"\n\
- end tell\n\
- ';
- function reloadSafari(callback) {
- var osa = spawn("osascript", ["-e", code]);
- var out = "";
- var err = "";
- osa.stdout.on('data', function (data) {
- out += data;
- });
- osa.stderr.on('data', function (data) {
- err += data;
- });
- osa.on('exit', function (code) {
- // Ignore stdout (which shows the return value of the AppleScript code)
- if (err.length > 0) {
- grunt.log.error("STDERR: "+err);
- }
- callback();
- });
- }
-
};
-
-
-
-
View
94 tools/watchdir.js
@@ -1,96 +1,6 @@
#!/usr/bin/env node
-var fs = require('fs');
-var spawn = require('child_process').spawn;
-var path = require('path');
-var _ = require("underscore");
-
-var extensions = {
- ".html": 1,
- ".css": 1,
-};
-var mtimes = {};
-var watchers = {};
+var jsreload = require("jsreload");
var dirname = process.argv[2];
-traverseFiles(dirname);
-
-function traverseFiles(dir) {
- fs.readdirSync(dir).forEach(function (filename) {
- var absolute = path.resolve(dir, filename);
-
- var stats = fs.statSync(absolute);
- if (stats.isDirectory()) {
- traverseFiles(absolute);
- } else if (stats.isFile()) {
- if (path.basename(absolute).indexOf(".") !== 0 && path.extname(absolute) in extensions) {
- console.log("WATCH: "+absolute);
- watchFile(absolute);
- }
- }
- });
-}
-
-function watchFile(filename) {
- // Most editors trigger a series of events whenever a single file is saved
- // Via debouncing, we only take action after the last event.
- watchers[filename] = fs.watch(filename, _.debounce(handleFileChanges.bind(null, filename), 250));
-}
-
-function handleFileChanges(absName, event, filename) {
- // On Mac OS X, filename is always null
-
- switch (event) {
- case 'rename':
- // Some editors (vi) rename the file when swapping it with the new version
- watchers[absName].close();
- if (fs.existsSync(absName)) {
- watchFile(absName);
- } else {
- // With debouncing, this shouldn’t happen, warn about it
- console.log("STOPPED WATCHING: "+absName);
- return;
- }
- fileChanged(event, absName);
- break;
- case 'change':
- fileChanged(event, absName);
- break;
- }
-}
-
-function fileChanged(event, absName) {
- // Check the date of last modification to make sure that there really was a change
- var mtime = +fs.statSync(absName).mtime;
- if (mtime !== mtimes[absName]) {
- mtimes[absName] = mtime;
- console.log(event.toUpperCase()+": "+absName);
- reloadSafari();
- }
-}
-
-// Inspiration: http://brettterpstra.com/watch-for-file-changes-and-refresh-your-browser-automatically/
-var code = '\
-tell application "Safari"\n\
- set mytab to first tab of first window\n\
- tell mytab to do javascript "window.location.reload()"\n\
-end tell\n\
-';
-function reloadSafari() {
- var osa = spawn("osascript", ["-e", code]);
- var out = "";
- var err = "";
- osa.stdout.on('data', function (data) {
- out += data;
- });
- osa.stderr.on('data', function (data) {
- err += data;
- });
- osa.on('exit', function (code) {
- // Ignore stdout (which shows the return value of the AppleScript code)
- if (err.length > 0) {
- console.log("STDERR: "+err);
- }
- console.log("RELOADED");
- });
-}
+jsreload.watchDir(dirname, jsreload.runReloadSafari);
View
7 tools/watchfile.js
@@ -0,0 +1,7 @@
+#!/usr/bin/env node
+
+var jsreload = require("jsreload");
+var fileName = process.argv[2];
+jsreload.runOpen(jsreload.safariAppName, fileName, function () {
+ jsreload.watchFile(fileName, jsreload.runReloadSafari);
+});
Please sign in to comment.
Something went wrong with that request. Please try again.