Commits

David Chambers committed 90ad9ac

Cakefile: add a task for running Hashify locally, and one for bundling scripts

  • Participants
  • Parent commits da2734c

Comments (0)

Files changed (7)

+fs = require 'fs'
+path = require 'path'
+
+express = require 'express'
+{parser, uglify} = require 'uglify-js'
+
+
+files = [
+  'ga.js'
+  'prettify.js'
+  'base64/base64.js'
+  'showdown/lib/showdown.js'
+  'showdown/lib/datetimes.js'
+  'showdown/lib/abbreviations.js'
+  'hashify-editor/hashify-editor.js'
+  'hashify.js'
+]
+
+option '-o', '--output [FILE]', 'write output to <file> instead of stdout'
+
+task 'build:scripts', 'concatenate and minify JavaScript files', (options) ->
+  {ast_mangle, ast_squeeze, gen_code} = uglify
+  data = (fs.readFileSync f, 'utf8' for f in files).join(';')
+  data = gen_code ast_squeeze ast_mangle parser.parse data
+
+  if options.output? then fs.writeFileSync options.output, data, 'utf8'
+  else console.log data
+
+task 'server', 'start the development server', ->
+  serve = (fn) -> (req, res) ->
+    filename = __dirname + fn req
+    path.exists filename, (exists) ->
+      if exists
+        res.sendfile filename
+      else
+        res.redirect '/' + Buffer('# 400 Bad Request').toString('base64')
+
+  app = express.createServer()
+  app.get /^[A-Za-z0-9+/=]*$/, serve -> '/index.html'
+  app.get /^unpack:[A-Za-z0-9]+(?:,[A-Za-z0-9]+)*$/, serve -> '/index.html'
+  app.get '*', serve (req) -> req.route.params[0]
+
+  port = process.env.PORT ? 3000
+  app.listen port, -> console.log "listening on port #{port}"

File LAB.js

-/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
-    v1.2.0 (c) Kyle Simpson
-    MIT License
-*/
-(function(p){var q="string",w="head",L="body",M="script",u="readyState",j="preloaddone",x="loadtrigger",N="srcuri",E="preload",Z="complete",y="done",z="which",O="preserve",F="onreadystatechange",ba="onload",P="hasOwnProperty",bb="script/cache",Q="[object ",bw=Q+"Function]",bx=Q+"Array]",e=null,h=true,i=false,k=p.document,bc=p.location,bd=p.ActiveXObject,A=p.setTimeout,be=p.clearTimeout,R=function(a){return k.getElementsByTagName(a)},S=Object.prototype.toString,G=function(){},r={},T={},bf=/^[^?#]*\//.exec(bc.href)[0],bg=/^\w+\:\/\/\/?[^\/]+/.exec(bf)[0],by=R(M),bh=p.opera&&S.call(p.opera)==Q+"Opera]",bi=("MozAppearance"in k.documentElement.style),bj=(k.createElement(M).async===true),v={cache:!(bi||bh),order:bi||bh||bj,xhr:h,dupe:h,base:"",which:w};v[O]=i;v[E]=h;r[w]=k.head||R(w);r[L]=R(L);function B(a){return S.call(a)===bw}function U(a,b){var c=/^\w+\:\/\//,d;if(typeof a!=q)a="";if(typeof b!=q)b="";d=((/^\/\//.test(a))?bc.protocol:"")+a;d=(c.test(d)?"":b)+d;return((c.test(d)?"":(d.charAt(0)==="/"?bg:bf))+d)}function bz(a){return(U(a).indexOf(bg)===0)}function bA(a){var b,c=-1;while(b=by[++c]){if(typeof b.src==q&&a===U(b.src)&&b.type!==bb)return h}return i}function H(t,l){t=!(!t);if(l==e)l=v;var bk=i,C=t&&l[E],bl=C&&l.cache,I=C&&l.order,bm=C&&l.xhr,bB=l[O],bC=l.which,bD=l.base,bn=G,J=i,D,s=h,m={},K=[],V=e;C=bl||bm||I;function bo(a,b){if((a[u]&&a[u]!==Z&&a[u]!=="loaded")||b[y]){return i}a[ba]=a[F]=e;return h}function W(a,b,c){c=!(!c);if(!c&&!(bo(a,b)))return;b[y]=h;for(var d in m){if(m[P](d)&&!(m[d][y]))return}bk=h;bn()}function bp(a){if(B(a[x])){a[x]();a[x]=e}}function bE(a,b){if(!bo(a,b))return;b[j]=h;A(function(){r[b[z]].removeChild(a);bp(b)},0)}function bF(a,b){if(a[u]===4){a[F]=G;b[j]=h;A(function(){bp(b)},0)}}function X(b,c,d,g,f,n){var o=b[z];A(function(){if("item"in r[o]){if(!r[o][0]){A(arguments.callee,25);return}r[o]=r[o][0]}var a=k.createElement(M);if(typeof d==q)a.type=d;if(typeof g==q)a.charset=g;if(B(f)){a[ba]=a[F]=function(){f(a,b)};a.src=c;if(bj){a.async=i}}r[o].insertBefore(a,(o===w?r[o].firstChild:e));if(typeof n==q){a.text=n;W(a,b,h)}},0)}function bq(a,b,c,d){T[a[N]]=h;X(a,b,c,d,W)}function br(a,b,c,d){var g=arguments;if(s&&a[j]==e){a[j]=i;X(a,b,bb,d,bE)}else if(!s&&a[j]!=e&&!a[j]){a[x]=function(){br.apply(e,g)}}else if(!s){bq.apply(e,g)}}function bs(a,b,c,d){var g=arguments,f;if(s&&a[j]==e){a[j]=i;f=a.xhr=(bd?new bd("Microsoft.XMLHTTP"):new p.XMLHttpRequest());f[F]=function(){bF(f,a)};f.open("GET",b);f.send("")}else if(!s&&a[j]!=e&&!a[j]){a[x]=function(){bs.apply(e,g)}}else if(!s){T[a[N]]=h;X(a,b,c,d,e,a.xhr.responseText);a.xhr=e}}function bt(a){if(typeof a=="undefined"||!a)return;if(a.allowDup==e)a.allowDup=l.dupe;var b=a.src,c=a.type,d=a.charset,g=a.allowDup,f=U(b,bD),n,o=bz(f);if(typeof d!=q)d=e;g=!(!g);if(!g&&((T[f]!=e)||(s&&m[f])||bA(f))){if(m[f]!=e&&m[f][j]&&!m[f][y]&&o){W(e,m[f],h)}return}if(m[f]==e)m[f]={};n=m[f];if(n[z]==e)n[z]=bC;n[y]=i;n[N]=f;J=h;if(!I&&bm&&o)bs(n,f,c,d);else if(!I&&bl)br(n,f,c,d);else bq(n,f,c,d)}function Y(a){if(t&&!I)K.push(a);if(!t||C)a()}function bu(a){var b=[],c;for(c=-1;++c<a.length;){if(S.call(a[c])===bx)b=b.concat(bu(a[c]));else b[b.length]=a[c]}return b}D={script:function(){be(V);var a=bu(arguments),b=D,c;if(bB){for(c=-1;++c<a.length;){if(B(a[c]))a[c]=a[c]();if(c===0){Y(function(){bt((typeof a[0]==q)?{src:a[0]}:a[0])})}else b=b.script(a[c]);b=b.wait()}}else{for(c=-1;++c<a.length;){if(B(a[c]))a[c]=a[c]()}Y(function(){for(c=-1;++c<a.length;){bt((typeof a[c]==q)?{src:a[c]}:a[c])}})}V=A(function(){s=i},5);return b},wait:function(a){be(V);s=i;if(!B(a))a=G;var b=H(t||J,l),c=b.trigger,d=function(){try{a()}catch(err){}c()};delete b.trigger;var g=function(){if(J&&!bk)bn=d;else d()};if(t&&!J)K.push(g);else Y(g);return b}};if(t){D.trigger=function(){var a,b=-1;while(a=K[++b])a();K=[]}}else D.trigger=G;return D}function bv(a){var b,c={},d={"UseCachePreload":"cache","UseLocalXHR":"xhr","UsePreloading":E,"AlwaysPreserveOrder":O,"AllowDuplicates":"dupe"},g={"AppendTo":z,"BasePath":"base"};for(b in d)g[b]=d[b];c.order=!(!v.order);for(b in g){if(g[P](b)&&v[g[b]]!=e)c[g[b]]=(a[b]!=e)?a[b]:v[g[b]]}for(b in d){if(d[P](b))c[d[b]]=!(!c[d[b]])}if(!c[E])c.cache=c.order=c.xhr=i;c.which=(c.which===w||c.which===L)?c.which:w;return c}p.$LAB={setGlobalDefaults:function(a){v=bv(a)},setOptions:function(a){return H(i,bv(a))},script:function(){return H().script.apply(e,arguments)},wait:function(){return H().wait.apply(e,arguments)}};(function(a,b,c){if(k[u]==e&&k[a]){k[u]="loading";k[a](b,c=function(){k.removeEventListener(b,c,i);k[u]=Z},i)}})("addEventListener","DOMContentLoaded")})(window);
-Copyright 2011 David Chambers. All rights reserved.
+Copyright 2011..2012 David Chambers. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

File README.markdown

+# Hashify
+
+Hashify does not solve a problem, it poses a question: what becomes possible
+when one is able to store entire documents in URLs?
+
+  - [Hashify overview](http://bit.ly/dXYxGU)
+  - [Hacker News thread](http://news.ycombinator.com/item?id=2464213)
+
+### Running Hashify locally
+
+    npm install
+    cake server
+    open http://127.0.0.1:3000
+
+### Deploying Hashify
+
+    hg pull --update
+    cake build:scripts
 
     dragging,
 
-    hashifyMe = location.protocol + '//' + location.hostname + '/',
+    hashifyMe = (function () {
+      var l = location, port = l.port;
+      return l.protocol + '//' + l.hostname + (port ? ':' + port : '') + '/';
+    }()),
 
     hashifyMeLen = hashifyMe.length,
 
       </div>
     </div>
     <div id=mask></div>
-    <script src=/LAB.js></script>
-    <script>
-      location.hostname === 'hashify.me'?
-        window.atob && window.btoa?
-          $LAB
-            .script('/concat.min.js'):
-          $LAB
-            .script('/base64/base64.min.js').wait()
-            .script('/concat.min.js'):
-        $LAB
-          .script('/ga.js')
-          .script('/prettify.js')
-          .script('/base64/base64.js')
-          .script('/showdown/lib/showdown.js').wait()
-          .script('/showdown/lib/datetimes.js')
-          .script('/showdown/lib/abbreviations.js')
-          .script('/hashify-editor/hashify-editor.js').wait()
-          .script('/hashify.js');
+    <script id=script>
+      !function() {
+        var files, insert, next
+        insert = function(src, onload) {
+          var script = document.createElement('script')
+          script.src = src
+          if (onload) script.onload = onload
+          document.body.insertBefore(script, document.getElementById('script'))
+        }
+        if (location.hostname == '127.0.0.1') {
+          files = [
+            '/prettify.js',
+            '/base64/base64.js',
+            '/showdown/lib/showdown.js',
+            '/showdown/lib/datetimes.js',
+            '/showdown/lib/abbreviations.js',
+            '/hashify-editor/hashify-editor.js',
+            '/hashify.js'
+          ]
+          next = function() { if (files.length) insert(files.shift(), next) }
+          next()
+        } else {
+          insert('/concat.min.js')
+        }
+      }()
     </script>
   </body>
 </html>

File package.json

+{
+  "name": "hashify.me",
+  "version": "1.0.0",
+  "description": "Store entire documents in URLs",
+  "author": "David Chambers <dc@hashify.me>",
+  "licenses": [{
+    "type": "BSD",
+    "url": "https://bitbucket.org/davidchambers/hashify.me/raw/default/LICENSE"
+  }],
+  "repository": {
+    "type": "hg",
+    "url": "https://bitbucket.org/davidchambers/hashify.me"
+  },
+  "devDependencies": {
+    "express": "2.5.x",
+    "uglify-js": "1.3.x"
+  }
+}