Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit cc44c676ac49e8f08658ee23f406608e02c0def5 @rsms committed Jul 28, 2010
Showing with 1,026 additions and 0 deletions.
  1. +27 −0 README.md
  2. +79 −0 basic-example.html
  3. +50 −0 browser-example.html
  4. +423 −0 hunchor.js
  5. +7 −0 pages/new-spotify-releases/index.md
  6. +13 −0 pages/qingdao-2010/index.md
  7. +8 −0 pages/scrup.md
  8. +419 −0 showdown.js
@@ -0,0 +1,27 @@
+# hunchor
+
+URL anchor aka "hash" triggering and browsing.
+
+See the `*-example.html` files.
+
+## MIT license
+
+Copyright (c) 2010 Rasmus Andersson <http://hunch.se/>
+
+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.
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Hunchor API</title>
+ <style type="text/css">
+ body {
+ background:white; color:#111; padding:0; margin:2em;
+ font-family:helvetica,sans-serif; font-size:18px; color:#999;
+ text-rendering: optimizelegibility;
+ }
+ img { border:none; }
+ a { color:#111; text-decoration:none; }
+ a:link:hover, a:active:hover { color:#006be4; }
+ a:visited:hover { color:#af00cf; }
+ p.hunchor-error {
+ padding-top:60px;
+ font-size:32px;
+ color:#f43;
+ display:none;
+ }
+ </style>
+ <script type="text/javascript"
+ src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
+ <script type="text/javascript" src="hunchor.js" charset="utf-8"></script>
+ <script type="text/javascript" charset="utf-8">
+ $(function(){
+ // Helpers for this example
+ var $m = $('#message');
+ function displayMessage(message, callee) {
+ $m.fadeOut(100, function(){
+ $m.html('<p>'+message+'</p>'+
+ '<p><strong>Handled by:</strong></p>'+
+ '<p><pre>'+callee+'</pre></p>').fadeIn(100);
+ });
+ }
+
+ // Fixed string match (in this case the empty string)
+ hunchor.on('', function(params, path, prevPath){
+ displayMessage('Requested the "index" page', arguments.callee);
+ });
+
+ // Web framework style pattern match
+ hunchor.on('pages/:slug', function(params, path, prevPath){
+ displayMessage('Requested the "'+params.slug+'" page',
+ arguments.callee);
+ });
+
+ // Regular expressions
+ hunchor.on(
+ /^posts\/(<year>\d{4})\/(<month>\d{2})\/(<day>\d{2})\/(<slug>.+)\/*$/,
+ function(params, path, prevPath){
+ displayMessage('Requested the post "'+params.slug+
+ '" for year '+params.year+', month '+params.month+
+ ' and day '+params.day
+ , arguments.callee);
+ });
+
+ // The later a handler is registered, the later it's chance to be invoked
+ hunchor.on(/.*/, function(params, path, prevPath){
+ displayMessage(
+ 'Match-all handler invoked (since no other handler matched)',
+ arguments.callee);
+ });
+ });
+ </script>
+ </head>
+ <body>
+ <p>Try these paths:</p>
+ <ul>
+ <li><a href="#">#</a></li>
+ <li><a href="#pages/about">pages/about</a></li>
+ <li><a href="#posts/2010/07/28/some-thing">posts/2010/07/28/some-thing</a></li>
+ <li><a href="#something/unknown">something/unknown</a></li>
+ </ul>
+ <h2>Output from the different handlers</h2>
+ <div id="message"></div>
+ </body>
+</html>
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Hunchor browser</title>
+ <style type="text/css">
+ body {
+ background:white; color:#111; padding:0; margin:2em;
+ font-family:helvetica,sans-serif; font-size:18px; color:#999;
+ text-rendering: optimizelegibility;
+ }
+ img { border:none; }
+ a { color:#111; text-decoration:none; }
+ a:link:hover, a:active:hover { color:#006be4; }
+ a:visited:hover { color:#af00cf; }
+ p.hunchor-error {
+ padding-top:60px;
+ font-size:32px;
+ color:#f43;
+ display:none;
+ }
+ </style>
+ <script type="text/javascript"
+ src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
+ <script type="text/javascript" src="hunchor.js" charset="utf-8"></script>
+ <script type="text/javascript" src="showdown.js" charset="utf-8"></script>
+ <script type="text/javascript" charset="utf-8">
+ $(function(){
+ $('#content').hunchorBrowser({
+ errorDisplay: $('p.hunchor-error'),
+ dirIndexSuffix: 'index.md',
+ breadcrumb: $('h2.breadcrumb'),
+ breadcrumbSeparator: "",
+ relativePathPrefix: 'pages/'
+ });
+ });
+ </script>
+ </head>
+ <body>
+ <h2 class="breadcrumb"><a href="#" class="root">Site title</a></h2>
+ <p class="hunchor-error">#url not found</p>
+ <div id="content">
+ <ul>
+ <li><a href="#scrup/index.md">scrup/index.md</a></li>
+ <li><a href="#qingdao-2010/">qingdao-2010/</a></li>
+ <li><a href="#index.html">index.html</a></li>
+ </ul>
+ </div>
+ </body>
+</html>
Oops, something went wrong.

5 comments on commit cc44c67

Have a look at http://github.com/blixt/js-hash and http://github.com/blixt/js-application, they do the same thing when used together, and may inspire you :) Also have a look at http://stackoverflow.com/questions/1078501/keeping-history-of-hash-anchor-changes-in-javascript for some research.

Owner

rsms replied Jul 28, 2010

Neat. Looks like what I wrote the first time (i.e. connected to DOM elements), but I rewrote the thing for the Dropular project and now later ripped out the code and put it up here after a request in the #node.js IRC channel.

Blixt, how do you trigger code based on anchor patterns without involving the DOM? E.g.

on('some/ting', function(){
  // run this code
})

?

Do you mean the Hash library? It's not connected to the DOM at all. The jQuery extension does add a global event which lets you attach it to DOM elements for the sake of simplicity, but you can just attach it to any object: $({}).hashchange(function () {}). Due to how jQuery is built, you should attach it to some kind of DOM object though, at the very least the document object (unbind etc. doesn't work when attaching to non-DOM objects).

Owner

rsms replied Jul 28, 2010

The example looks DOM-bound... (I admit I haven't looked into the code yet, just read the readme)

Inline questions:

function handler(newHash, initial) {
  // <snip>
}
// 1. Why put the handler first? Makes inlining handlers (as they should be
//    imho) hard to read. In nodejs it was discussed and later decided that
//    callbacks/handlers always come last in argument lists.
//
// 2. What does the second argument mean? Why a hidden iframe? Is there a
//    hidden agenda (e.g. poor browsers cross-domain communication) or am I
//    just missing something obvious?
Hash.init(handler, document.getElementById('hidden-iframe'));
// 3. What does this mean? Shortcut for document.location.hash = "abc123"?
Hash.go('abc123');

You saw the jQuery one I guess. The barebones example is Hash.init(function (newHash) { alert(newHash); }); – no DOM involved :)

  1. Good point. The iframe argument is optional, that's why it's last. I could just make the code use the first function argument as the handler and the first <iframe> reference argument as the iframe.
  2. See my research post. Basically, hash history doesn't exist in certain browsers, but it can be simulated by messing with an <iframe>. It's optional though, so you can choose not to support these obsolete browsers by simply not passing in an iframe reference.
  3. Kind of. It calls the callback etc. too, making it more responsive (since for browsers without the onhashchange event you have to poll for changes.) So it's just a convenient function to use instead of location.hash, which improves performance very slightly.
Please sign in to comment.