Full Code of andrewdavey/vogue for AI

master 46e38b373c7a cached
16 files
22.5 KB
6.2k tokens
12 symbols
1 requests
Download .txt
Repository: andrewdavey/vogue
Branch: master
Commit: 46e38b373c7a
Files: 16
Total size: 22.5 KB

Directory structure:
gitextract_lf45wp7e/

├── .gitignore
├── demo/
│   ├── index.htm
│   ├── novogue.htm
│   ├── styles/
│   │   ├── demo.css
│   │   ├── print.css
│   │   └── reset.css
│   └── sub/
│       └── index.htm
├── license.txt
├── readme.md
└── src/
    ├── README.md
    ├── VogueClient.js
    ├── Watcher.js
    ├── client/
    │   ├── about.htm
    │   └── vogue-client.js
    ├── package.json
    └── vogue.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.swp
src/node_modules


================================================
FILE: demo/index.htm
================================================
<!DOCTYPE html>
<html>
  <head>
    <title>Vogue - Demo Page</title>
    <link href="/styles/reset.css" type="text/css" rel="stylesheet"/>
    <link href="/styles/demo.css?test=1" type="text/css" rel="stylesheet"/>
    <link href="/styles/print.css" type="text/css" rel="stylesheet" media="print"/>
  </head>
  <body>
    <h1>Vogue - Demo Page</h1>
    <p>This is some demo text for Vogue</p>
    <p>The vogue client is already added to this page. Try editing the CSS files to see
    the page update.<p>
    <script type="text/javascript" src="http://localhost:8001/vogue-client.js?base=http://localhost:8001/"></script>
  </body>
</html>


================================================
FILE: demo/novogue.htm
================================================
<!DOCTYPE html>
<html>
  <head>
    <title>Vogue - Demo Page</title>
    <link href="/styles/reset.css" type="text/css" rel="stylesheet"/>
    <link href="/styles/demo.css?test=1" type="text/css" rel="stylesheet"/>
  </head>
  <body>
    <h1>Vogue - Demo Page</h1>
    <p>This is some demo text for Vogue</p>
    <p>Vogue has not been loaded into this page. Try using the favlet.</p>

    <script type="text/javascript">
      // a dummy script to make sure the injected Vogue script can detect itself correctly
    </script>
  </body>
</html>


================================================
FILE: demo/styles/demo.css
================================================
body {
  background-color: #fff;
  color: #000;
  font-family: sans-serif;
  padding: 10px;
}


================================================
FILE: demo/styles/print.css
================================================
body {
  background: #f0f; /* something nasty to notice if vogue switches on this style! */
  color: blue;
}


================================================
FILE: demo/styles/reset.css
================================================
* { padding: 0; margin: 0 }


================================================
FILE: demo/sub/index.htm
================================================
<!DOCTYPE html>
<html>
  <head>
    <title>Vogue - Demo Page</title>
    <link href="/styles/reset.css" type="text/css" rel="stylesheet"/>
    <link href="/styles/demo.css?test=1" type="text/css" rel="stylesheet"/>
  </head>
  <body>
    <h1>Vogue - Demo Page</h1>
    <p>This is some demo text for Vogue</p>
    <p>The vogue client is already added to this page. Try editing the CSS files to see
    the page update.<p>
    <script type="text/javascript" src="http://localhost:8001/vogue-client.js"></script>
  </body>
</html>


================================================
FILE: license.txt
================================================
Copyright (c) 2011 Andrew Davey (andrew@equin.co.uk)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: readme.md
================================================
# Vogue

Vogue creates a real-time link between your web browser and your file system. When you save 
a CSS file, used by the HTML page in your browser, Vogue will make the browser reload the 
stylesheet. Only the stylesheet is reloaded, not the entire page, making it work
even for very dynamic/ajax pages.

Vogue is all javascript. It runs a server on [Node.js](http://nodejs.org/), 
which will watch the file system. 
The server accepts WebSocket connections from the client code 
(which uses [socket.io](http://socket.io/)).
The client javascript can be loaded into a HTML page using a single script tag.

## Install using npm
Make sure you have Node.JS and [npm](http://npmjs.org/) installed.  
Then run: 

    npm install vogue -g

## Usage
Run the Vogue server.

    vogue --port 8001 /path/to/website

`--port` : The port used for Vogue's HTTP server. Optional, defaults to 8001.

`--rewrite` : A rule in the form of "regexp:replacement" (e.g. "v[0-9]/(.*)$:files/\$1" ) to rewrite urls to filesystem paths.
 Submatches such as $1 will probably need to entered in your shell as \$1 to escape the $. 

Open http://localhost:8001/ to see instructions for loading the Vogue client into your
web pages.

## Demo
Vogue runs a separate HTTP server to the one running your website.
To run the demo website, for example, do something like this first:
  
    cd demo  
    python -m SimpleHTTPServer

Then, from another terminal session, run Vogue:

    vogue demo

Open http://localhost:8000 (or whatever the port used by your web server is) 
to view the demo index page. The demo page has the Vogue client javascript already included.
So it will connect to the Vogue server and be watching the two CSS files used by the page.

Try editing the CSS files in the `demo/styles` directory. Whenever you save, you will see the 
browser update the reflect the changes made. This is done without reloading the entire page.

Copyright &copy; 2011 Andrew Davey (andrew@equin.co.uk)


================================================
FILE: src/README.md
================================================
# Vogue

Vogue creates a real-time link between your web browser and your file system. When you save 
a CSS file, used by the HTML page in your browser, Vogue will make the browser reload the 
stylesheet. Only the stylesheet is reloaded, not the entire page, making it work
even for very dynamic/ajax pages.

## Usage
Run the Vogue server.

    vogue --port 8001 /path/to/website

`--port` : The port used for Vogue's HTTP server. Optional, defaults to 8001.

`--rewrite` : A rule in the form of "regexp:replacement" (e.g. `v[0-9]/(.*)$:files/\$1` ) to rewrite urls to filesystem paths.
 Submatches such as $1 will probably need to entered in your shell as \$1 to escape the $. 

Open http://localhost:8001/ to see instructions for loading the Vogue client into your
web pages.




================================================
FILE: src/VogueClient.js
================================================
var fs = require('fs');

exports.VogueClient = VogueClient;

// Encapsulates a web socket client connection from a web browser.
function VogueClient(clientSocket, watcher) {
  this.socket = clientSocket;
  this.watcher = watcher;
  this.watchedFiles = {};
  clientSocket.on('watch', this.handleMessage.bind(this));
  clientSocket.on('disconnect', this.disconnect.bind(this));
}

// Parse an incoming message from the client and dispatch accordingly.
VogueClient.prototype.handleMessage = function(data) {
  this.watchFile(data.href);
};

VogueClient.prototype.watchFile = function(href) {
  var filename = this.watcher.getFilenameForHref(href);
  fs.stat(filename, function(err, stats) {
    if (err) {
      console.log('Could not read stats for ' + filename);
      return;
    }
    
    this.watchedFiles[filename] = {
      href: href,
      mtime: stats.mtime
    };
    this.watcher.startWatching(filename);
  }.bind(this));
};

VogueClient.prototype.updateFile = function(filename) {
  var fileInfo = this.watchedFiles[filename];
  if (fileInfo) {
    fs.stat(filename, function(err, stats) {
      if (err) {
        console.error('Could not read stats for file: ' + filename);
        return;
      }
      // Only send message to client if the file was modified
      // since we last saw it.
      if (fileInfo.mtime < stats.mtime) {
        this.socket.emit('update', { href: fileInfo.href });
        fileInfo.mtime = stats.mtime;
      }
    }.bind(this));
  }
};

VogueClient.prototype.disconnect = function() {
  for (var filename in this.watchedFiles) {
    this.watcher.stopWatching(filename);
  }
  this.watcher.removeClient(this);
};


================================================
FILE: src/Watcher.js
================================================
var fs   = require('fs')
  , path = require('path');

exports.Watcher = Watcher;

function Watcher(webDirectory, rewrite) {
  this.webDirectory = webDirectory;
  // array of VogueClient objects
  this.clients = [];
  
  // filename -> number_of_clients_watching 
  this.fileWatcherCount = {};

  if (rewrite) {
    this.rewriteUrlToPath = createRewriter(rewrite); 
  }

  function createRewriter(rewrite) {
    var parts = rewrite.split(':');
    if (parts.length === 2) {
      var regex = new RegExp(parts[0]);
      var replacement = parts[1];
      return function (str) { 
        return str.replace(regex, replacement);
      }
    } else {
      throw new Error('Rewrite must be of the form "regex:replacement".');
    }
  }
}

Watcher.prototype.addClient = function(client) {
  this.clients.push(client);
};

Watcher.prototype.removeClient = function(client) {
  this.clients.splice(this.clients.indexOf(client), 1);
};

Watcher.prototype.getFilenameForHref = function(href) {
  if (this.rewriteUrlToPath) {
    href = this.rewriteUrlToPath(href);
  }
  // Remove any querystring junk.
  // e.g. "foo/bar.css?abc=123" --> "foo/bar.css"
  href = href.split('?')[0];
  var filename = path.join(this.webDirectory, href);
  return filename;
};

Watcher.prototype.startWatching = function(filename) {
  console.log('Watching file: ' + filename);
  if (filename in this.fileWatcherCount) {
    // already watching this file, so just increment the client count.
    this.fileWatcherCount[filename]++;
  } else {
    fs.watchFile(
      filename,
      { persistent: true, interval: 50 },
      fileChanged.bind(this)
    );
    this.fileWatcherCount[filename] = 1;
  }

  function fileChanged() {
    console.log('File changed: ' + filename);
    this.clients.forEach(function(client) {
      client.updateFile(filename);
    });
  }
};

Watcher.prototype.stopWatching = function(filename) {
  if (!(filename in this.fileWatcherCount)) return;

  var watcherCount = --this.fileWatcherCount[filename];
  if (watcherCount == 0) {
    delete this.fileWatcherCount[filename];
    fs.unwatchFile(filename);
    console.log('Stopped watching file: ' + filename);
  }
}



================================================
FILE: src/client/about.htm
================================================
<!DOCTYPE html>
<html>
  <head>
    <title>Vogue</title>
  </head>
  <body>
    <h1>Vogue</h1>
    <p>
    Add this bookmarklet to your bookmarks. It will inject Vogue's scripts
    into the currently running page.
    </p>
    <p>
      <a id="favlet">Inject Vogue</a>
    </p>
    <p>
    Or, add the following script into your HTML.
    </p>
    <pre>&lt;script src="http://localhost:{port}/vogue-client.js" type="text/javascript"&gt;&lt;/script&gt;</pre>
    <p>Note: This should only appear in development-time code. Remove before going into production.</p>
    <script type="text/javascript">
      var favlet = document.getElementById("favlet");
      favlet.href = "javascript:(function(){\
if (typeof window.__vogue__!=='undefined') return;\
window.__vogue__ = {\
rootUrl:'http://localhost:{port}/',\
domain:'localhost',\
port:{port}\
};\
var s = document.createElement('script');\
s.setAttribute('src', 'http://localhost:{port}/vogue-client.js');\
s.setAttribute('type', 'text/javascript');\
document.getElementsByTagName('head')[0].appendChild(s);\
})()".replace(/\r\n|\r|\n/g, "");
    </script>
  </body>
</html>


================================================
FILE: src/client/vogue-client.js
================================================
// Vogue - Client
// Copyright (c) 2011 Andrew Davey (andrew@equin.co.uk)
(function () {
  var script,
      hop = Object.prototype.hasOwnProperty,
      head = document.getElementsByTagName("head")[0];

  function vogue() {
    var stylesheets,
        socket = io.connect(script.rootUrl);

    /**
     * Watch for all available stylesheets.
     */
    function watchAllStylesheets() {
      var href;
      for (href in stylesheets) {
        if (hop.call(stylesheets, href)) {
          socket.emit("watch", {
            href: href
          });
        }
      }
    }

    /**
     * Reload a stylesheet.
     *
     * @param {String} href The URL of the stylesheet to be reloaded.
     */
    function reloadStylesheet(href) {
      var newHref = stylesheets[href].href +
            (href.indexOf("?") >= 0 ? "&" : "?") +
            "_vogue_nocache=" + (new Date).getTime(),
          stylesheet;
      // Check if the appropriate DOM Node is there.
      if (!stylesheets[href].setAttribute) {
        // Create the link.
        stylesheet = document.createElement("link");
        stylesheet.setAttribute("rel", "stylesheet");
        stylesheet.setAttribute("href", newHref);
        head.appendChild(stylesheet);

        // Update the reference to the newly created link.
        stylesheets[href] = stylesheet;
      } else {
        // Update the href to the new URL.
        stylesheets[href].href = newHref;
      }
    }


    /**
     * Handle messages from socket.io, and load the appropriate stylesheet.
     *
     * @param message Socket.io message object.
     * @param message.href The url of the stylesheet to be loaded.
     */
    function handleMessage(message) {
      reloadStylesheet(message.href);
    }

    /**
     * Fetch all the local stylesheets from the page.
     *
     * @returns {Object} The list of local stylesheets keyed by their base URL.
     */
    function getLocalStylesheets() {

      /**
       * Checks if the stylesheet is local.
       *
       * @param {Object} link The link to check for.
       * @returns {Boolean}
       */
      function isLocalStylesheet(link) {
        var href, i, isExternal = true;
        if (link.getAttribute("rel") !== "stylesheet") {
          return false;
        }
        href = link.href;

        for (i = 0; i < script.bases.length; i += 1) {
          if (href.indexOf(script.bases[i]) > -1) {
            isExternal = false;
            break;
          }
        }

        return !(isExternal && href.match(/^https?:/));
      }

      /**
       * Checks if the stylesheet's media attribute is 'print'
       *
       * @param (Object) link The stylesheet element to check.
       * @returns (Boolean)
       */
      function isPrintStylesheet(link) {
        return link.getAttribute("media") === "print";
      }

      /**
       * Get the link's base URL.
       *
       * @param {String} href The URL to check.
       * @returns {String|Boolean} The base URL, or false if no matches found.
       */
      function getBase(href) {
        var base, j;
        for (j = 0; j < script.bases.length; j += 1) {
          base = script.bases[j];
          if (href.indexOf(base) > -1) {
            return href.substr(base.length);
          }
        }
        return false;
      }

      function getProperty(property) {
        return this[property];
      }

      var stylesheets = {},
          reImport = /@import\s+url\(["']?([^"'\)]+)["']?\)/g,
          links = document.getElementsByTagName("link"),
          link, href, matches, content, i, m;

      // Go through all the links in the page, looking for stylesheets.
      for (i = 0, m = links.length; i < m; i += 1) {
        link = links[i];
        if (isPrintStylesheet(link)) continue;
        if (!isLocalStylesheet(link)) continue;
        // Link is local, get the base URL.
        href = getBase(link.href);
        if (href !== false) {
          stylesheets[href] = link;
        }
      }

      // Go through all the style tags, looking for @import tags.
      links = document.getElementsByTagName("style");
      for (i = 0, m = links.length; i < m; i += 1) {
        if (isPrintStylesheet(links[i])) continue;
        content = links[i].text || links[i].textContent;
        while ((matches = reImport.exec(content))) {
          link = {
            rel: "stylesheet",
            href: matches[1],
            getAttribute: getProperty
          };
          if (isLocalStylesheet(link)) {
            // Link is local, get the base URL.
            href = getBase(link.href);
            if (href !== false) {
              stylesheets[href] = link;
            }
          }
        }
      }
      return stylesheets;
    }

    stylesheets = getLocalStylesheets();
    socket.on("connect", watchAllStylesheets);
    socket.on("update", handleMessage);
  }

  /**
   * Load a script into the page, and call a callback when it is loaded.
   *
   * @param {String} src The URL of the script to be loaded.
   * @param {Function} loadedCallback The function to be called when the script is loaded.
   */
  function loadScript(src, loadedCallback) {
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.setAttribute("src", src);

    // Call the callback when the script is loaded.
    script.onload = loadedCallback;
    script.onreadystatechange = function () {
      if (this.readyState === "complete" || this.readyState === "loaded") {
        loadedCallback();
      }
    };

    head.appendChild(script);
  }

  /**
   * Load scripts into the page, and call a callback when they are loaded.
   *
   * @param {Array} scripts The scripts to be loaded.
   * @param {Function} loadedCallback The function to be called when all the scripts have loaded.
   */
  function loadScripts(scripts, loadedCallback) {
    var srcs = [], property, count, i, src,
        countDown = function () {
          count -= 1;
          if (!count) {
            loadedCallback();
          }
        };

    for (property in scripts) {
      if (!(property in window)) {
        srcs.push(scripts[property]);
      }
    }

    count = srcs.length;
    if (!count) {
      loadedCallback();
    }

    for (i = 0; i < srcs.length; i += 1) {
      src = srcs[i];
      loadScript(src, countDown);
    }
  }

  /**
   * Fetches the info for the vogue client.
   */
  function getScriptInfo() {
    var bases = [ document.location.protocol + "//" + document.location.host ],
        scripts, src, rootUrl, baseMatch;
    if (typeof window.__vogue__ === "undefined") {
      scripts = document.getElementsByTagName("script");
      for (var i=0; i < scripts.length; i++) {
        src = scripts[i].getAttribute("src");
        if (src && src.slice(-15) === 'vogue-client.js') break;
      }
      rootUrl = src.match(/^https?\:\/\/(.*?)\//)[0];
      // There is an optional base argument, that can be used.
      baseMatch = src.match(/\bbase=(.*)(&|$)/);

      if (baseMatch) {
        bases = bases.concat(baseMatch[1].split(","));
      }
      return {
        rootUrl: rootUrl,
        bases: bases
      };
    } else {
      window.__vogue__.bases = bases;
      return window.__vogue__;
    }
  }

  /**
   * Fetches the port from the URL.
   *
   * @param {String} url URL to get the port from
   * @returns {Number} The port number, or 80 if no port number found or is invalid.
   */
  function getPort(url) {
    // URL may contain the port number after the second colon.
    // http://domain:1234/
    var index = url.indexOf(":", 6); // skipping 6 characters to ignore first colon
    return index < 0 ? 80 : parseInt(url.substr(index + 1), 10);
  }

  script = getScriptInfo();
  loadScripts({
    io: script.rootUrl + "socket.io/socket.io.js"
  }, vogue);
}());


================================================
FILE: src/package.json
================================================
{
  "name": "vogue",
  "description": "Auto-reload stylesheets in web browser whenever the CSS files are saved.",
  "version": "0.5.0",
  "homepage": "http://github.com/andrewdavey/vogue",
  "repository": "http://github.com/andrewdavey/vogue.git",
  "author": "Andrew Davey <andrew@equin.co.uk> (http://aboutcode.net/)",
  "directories": {
    "lib": ""
  },
  "engines": {
    "node": "*"
  },
  "bin": {
    "vogue": "./vogue.js"
  },
  "dependencies": {
    "socket.io": ">=0.9.0",
    "parseopt": ">=1.0.0"
  }
}


================================================
FILE: src/vogue.js
================================================
#!/usr/bin/env node
/* vogue.js
 * A tool for web developers. Vogue watches for changes to CSS files and
 * informs the web browser using them to reload those stylesheets.
 * 
 * Created by Andrew Davey ~ http://aboutcode.net 
 *
 * Vogue runs on nodeJS and uses socket.io for real-time communication between
 * browser and server.
 */

var http = require('http')
  , fs   = require('fs')
  , path = require('path')
  , url  = require('url')
  , opt  = require('parseopt')
  , io   = require('socket.io');

var VogueClient = require('./VogueClient').VogueClient
  , Watcher     = require('./Watcher').Watcher;

var options = getOptions()
  , server  = http.createServer(handleHttpRequest)
  , socket  = io.listen(server)
  , watcher = new Watcher(options.webDirectory,options.rewrite);

server.listen(options.port);
socket.sockets.on('connection', function(clientSocket) {
  watcher.addClient(new VogueClient(clientSocket, watcher));
});

console.log('Watching directory: ' + options.webDirectory);
console.log('Listening for clients: http://localhost:' + options.port + '/');


function handleHttpRequest(request, response) {
  var pathname = url.parse(request.url).pathname;
  if (pathname === '/') {
    sendAboutPage(response);
  } else if (pathname === '/vogue-client.js') {
    sendVogueClient(response);
  }
}

function sendAboutPage(response) {
  fs.readFile(__dirname + '/client/about.htm', function(e, fileData) {
    var html = fileData.toString();
    html = html.replace(/\{port\}/g, options.port.toString());
    response.writeHead(200, { 'Content-Type': 'text/html' });
    response.write(html);
    response.end();
  });
}

function sendVogueClient(response) {
  fs.readFile(__dirname + '/client/vogue-client.js', function(e, fileData) {
    var script = fileData.toString();
    response.writeHead(200, { 'Content-Type': 'text/javascript' });
    response.write(script);
    response.end();
  });
}

function getOptions() {
  var data = createOptionParser().parse();
  if (!data) process.exit(1); // Some kind of parsing error

  // The directory to watch is given as the first argument after the options.
  // So we'll put it into the options we return for simplicity.
  data.options.webDirectory = getDirectoryToWatch(data.arguments);
  return data.options;

  function createOptionParser() {
    var parser = new opt.OptionParser({
      options: [
        {
          name: ['--port', '-p'],
          type: 'int',
          help: 'Port to run Vogue server on',
          'default': 8001
        },
        {
          name: ['--rewrite', '-r'],
          type: 'string',
          help: 'Expression of the form "regexp:replacement" rewrites a URL path into a file system path, relative to the website root directory. For example: --rewrite "v[0-9]/(.*)$:files/\\$1" would change "v1/demo.css" to "files/demo.css".',
          'default': null
        },
        {
          name: ['--help','-h','-?'],
          type: 'flag',
          help: 'Show this help message',
          onOption: function (value) {
            if (value) {
              parser.usage('First argument after options should be the path to the website\'s root directory. Otherwise the current directory is used.\ne.g. vogue -p 8001 ./myweb');
            }
            // returning true cancels any further option parsing
            // and parser.parse() returns null
            return value;
          }
        }
      ]
    });
    return parser;
  }

  function getDirectoryToWatch(arguments) {
    var dir;
    if (arguments.length > 0) {
      if (/^\//.test(arguments[0])) {
        dir = arguments[0];
      } else {
        dir = path.join(process.cwd(), arguments[0]);
      }
    } else {
      dir = process.cwd();
    }

    try {
      var stats = fs.statSync(dir);
      if (!stats.isDirectory()) {
        console.error('Path is not a directory: ' + dir);
        process.exit(1);
      }
    } catch (e) {
      console.error('Path not found: ' + dir);
      process.exit(1);
    }

    return dir;
  }
}
Download .txt
gitextract_lf45wp7e/

├── .gitignore
├── demo/
│   ├── index.htm
│   ├── novogue.htm
│   ├── styles/
│   │   ├── demo.css
│   │   ├── print.css
│   │   └── reset.css
│   └── sub/
│       └── index.htm
├── license.txt
├── readme.md
└── src/
    ├── README.md
    ├── VogueClient.js
    ├── Watcher.js
    ├── client/
    │   ├── about.htm
    │   └── vogue-client.js
    ├── package.json
    └── vogue.js
Download .txt
SYMBOL INDEX (12 symbols across 4 files)

FILE: src/VogueClient.js
  function VogueClient (line 6) | function VogueClient(clientSocket, watcher) {

FILE: src/Watcher.js
  function Watcher (line 6) | function Watcher(webDirectory, rewrite) {
  function fileChanged (line 65) | function fileChanged() {

FILE: src/client/vogue-client.js
  function vogue (line 8) | function vogue() {
  function loadScript (line 175) | function loadScript(src, loadedCallback) {
  function loadScripts (line 197) | function loadScripts(scripts, loadedCallback) {
  function getScriptInfo (line 226) | function getScriptInfo() {
  function getPort (line 258) | function getPort(url) {

FILE: src/vogue.js
  function handleHttpRequest (line 36) | function handleHttpRequest(request, response) {
  function sendAboutPage (line 45) | function sendAboutPage(response) {
  function sendVogueClient (line 55) | function sendVogueClient(response) {
  function getOptions (line 64) | function getOptions() {
Condensed preview — 16 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (25K chars).
[
  {
    "path": ".gitignore",
    "chars": 23,
    "preview": "*.swp\nsrc/node_modules\n"
  },
  {
    "path": "demo/index.htm",
    "chars": 640,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Vogue - Demo Page</title>\n    <link href=\"/styles/reset.css\" type=\"text/css\" "
  },
  {
    "path": "demo/novogue.htm",
    "chars": 544,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Vogue - Demo Page</title>\n    <link href=\"/styles/reset.css\" type=\"text/css\" "
  },
  {
    "path": "demo/styles/demo.css",
    "chars": 94,
    "preview": "body {\n  background-color: #fff;\n  color: #000;\n  font-family: sans-serif;\n  padding: 10px;\n}\n"
  },
  {
    "path": "demo/styles/print.css",
    "chars": 109,
    "preview": "body {\n  background: #f0f; /* something nasty to notice if vogue switches on this style! */\n  color: blue;\n}\n"
  },
  {
    "path": "demo/styles/reset.css",
    "chars": 28,
    "preview": "* { padding: 0; margin: 0 }\n"
  },
  {
    "path": "demo/sub/index.htm",
    "chars": 528,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Vogue - Demo Page</title>\n    <link href=\"/styles/reset.css\" type=\"text/css\" "
  },
  {
    "path": "license.txt",
    "chars": 1077,
    "preview": "Copyright (c) 2011 Andrew Davey (andrew@equin.co.uk)\n\nPermission is hereby granted, free of charge, to any person obtain"
  },
  {
    "path": "readme.md",
    "chars": 1973,
    "preview": "# Vogue\n\nVogue creates a real-time link between your web browser and your file system. When you save \na CSS file, used b"
  },
  {
    "path": "src/README.md",
    "chars": 780,
    "preview": "# Vogue\n\nVogue creates a real-time link between your web browser and your file system. When you save \na CSS file, used b"
  },
  {
    "path": "src/VogueClient.js",
    "chars": 1655,
    "preview": "var fs = require('fs');\n\nexports.VogueClient = VogueClient;\n\n// Encapsulates a web socket client connection from a web b"
  },
  {
    "path": "src/Watcher.js",
    "chars": 2165,
    "preview": "var fs   = require('fs')\n  , path = require('path');\n\nexports.Watcher = Watcher;\n\nfunction Watcher(webDirectory, rewrite"
  },
  {
    "path": "src/client/about.htm",
    "chars": 1126,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Vogue</title>\n  </head>\n  <body>\n    <h1>Vogue</h1>\n    <p>\n    Add this book"
  },
  {
    "path": "src/client/vogue-client.js",
    "chars": 7812,
    "preview": "// Vogue - Client\n// Copyright (c) 2011 Andrew Davey (andrew@equin.co.uk)\n(function () {\n  var script,\n      hop = Objec"
  },
  {
    "path": "src/package.json",
    "chars": 517,
    "preview": "{\n  \"name\": \"vogue\",\n  \"description\": \"Auto-reload stylesheets in web browser whenever the CSS files are saved.\",\n  \"ver"
  },
  {
    "path": "src/vogue.js",
    "chars": 4016,
    "preview": "#!/usr/bin/env node\n/* vogue.js\n * A tool for web developers. Vogue watches for changes to CSS files and\n * informs the "
  }
]

About this extraction

This page contains the full source code of the andrewdavey/vogue GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 16 files (22.5 KB), approximately 6.2k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!