Skip to content

Instantly share code, notes, and snippets.

@hallettj
Created June 23, 2011 01:59
Show Gist options
  • Save hallettj/1041736 to your computer and use it in GitHub Desktop.
Save hallettj/1041736 to your computer and use it in GitHub Desktop.
define()
/**
* Minimal implementation of Modules/AsynchronousDefinition as described
* in http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition
*
* For a more complete implementation use RequireJS
* <http://requirejs.org/>.
*/
var define = (function() {
var definitions = {},
pending = [];
/**
* Given a list and a predicate, returns a pair of lists where the
* first list contains all elements of the original list for which
* the predicate evaluated to true, and the second returned list
* contains other elements from the original list.
*/
function partition(predicate, list) {
var passed = list.filter(predicate);
var failed = list.filter(function(e) {
return !predicate(e);
});
return [passed, failed];
}
function addDefinition(id, object) {
if (id) {
definitions[id] = object;
}
}
function dependenciesFor(module) {
return module.dependencies.map(function(id) {
return definitions[id];
}).filter(function(dep) {
return !!dep;
});
}
function runPending() {
var partitioned = partition(function(module) {
return dependenciesFor(module).length !== module.dependencies.length;
}, pending);
pending = partitioned[0];
var satisfied = partitioned[1];
satisfied.forEach(function(module) {
var dependencies = dependenciesFor(module);
addDefinition(module.id, module.factory.apply(null, dependencies));
});
if (satisfied.length > 0) {
runPending();
}
}
function define(/* [id], [dependencies], factory */) {
var id, dependencies, factory
, args = Array.prototype.slice.call(arguments)
, asyncModule;
if (args.length > 1 && typeof args[0] == 'string') {
id = args.shift();
}
if (args.length > 1 && args[0] && typeof args[0].length == 'number') {
dependencies = args.shift();
}
factory = args.shift();
if (typeof factory == 'function') {
pending.push({
id: id,
dependencies: dependencies || [],
factory: factory
});
runPending();
} else if (factory) {
addDefinition(id, factory);
runPending();
} else {
throw "no module definition was given";
}
}
define.amd = {};
return define;
})();
define('injectScript', function() {
var noop = function() {};
return function(src, callback) {
var scripts = document.getElementsByTagName('script')
, firstScript = scripts[0]
, head = firstScript.parentNode // element that contains scripts - not necessarily head tag
, script = document.createElement('script');
script.src = src;
script.onreadystatechange = script.onload = function() {
if (!script.readyState || script.readyState == 'loaded' || script.readyState == 'complete') {
script.onload = script.onreadystatechange = noop;
head.removeChild(script);
if (callback) { callback(); }
}
};
head.insertBefore(script, firstScript);
};
});
define(['injectScript'], function(inject) {
inject('https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js', function() {
// Defines a module that provides jQuery when jQuery is finished
// loading.
define('jQuery', function() { return jQuery; });
});
});
define('rhinautheros.jquery', ['rhinautheros', 'jQuery'], function(rhino, $) {
// function signedXHR(options, originalOptions, jqXHR) {
// return {
// send: function(headers, completeCallback) {
// [> completeCallback(status, statusText, responses, headers); <]
// },
// abort: function() {
// }
// };
// }
function signXHR(options, originalOptions, jqXHR) {
var auth, body;
if (options.oauth) {
body = options.type == 'GET' ? '' : options.data;
auth = rhino.authorization(options.type, options.url, body);
options.headers.Authorization = auth;
}
}
$.ajaxPrefilter(signXHR);
});
define('rhinautheros', ['jsSHA', 'url'], function(jsSHA, URL) {
var accessToken = {
access_token: 'not secret',
token_type: 'mac',
expires_in: 3600,
refresh_token: 'another secret',
mac_key: 'secret',
mac_algorithm: 'hmac-sha-256',
issue_time: 2359082350
};
/**
* Returns a string identifier of the specific hash algorithm to use
* based on the mac_algorithm property of the access token.
*/
function hashAlgorithm() {
var matches = accessToken.mac_algorithm.match(/(sha-\d+)/i);
return matches[1].toUpperCase();
}
/**
* Returns a hash of the given string using Base64 encoding. The
* hash algorithm used is determined by details of the access token
* provided by the server.
*/
function hash(text) {
var shaObj = new jsSHA(text, 'ASCII');
return shaObj.getHash(hashAlgorithm(), 'B64');
}
function hmac(text) {
var shaObj = new jsSHA(text, 'ASCII');
return shaObj.getHMAC(accessToken.access_token, 'ASCII', hashAlgorithm(), 'B64');
}
function getNonce() {
var age = Math.round((new Date() - new Date(accessToken.issue_time)) / 1000)
, random = Math.round(Math.random() * 99999999);
return String(age) +':'+ String(random);
}
function normalizedRequestString(nonce, method, url, bodyhash, ext) {
var location = URL.parse(url);
return [
nonce,
method.toUpperCase(),
location.pathname + location.search,
location.host,
location.port,
bodyhash,
ext || ""
].map(function(e) {
return e + "\n";
}).join("");
}
return {
/**
* Returns a string that should be set as the value of the
* Authorization header on a request.
*/
authorization: function(method, url, body, ext) {
var nonce = getNonce()
, bodyhash = body ? hash(body) : ""
, requestString = normalizedRequestString(nonce, method, url, bodyhash, ext)
, mac = hmac(requestString);
var params = [
['id', accessToken.access_token],
['nonce', nonce],
['bodyhash', bodyhash],
['mac', mac],
['ext', ext]
];
return "MAC "+ params.filter(function(param) {
return !!param[1]; // filter out bodyhash and ext if they are empty
}).map(function(param) {
return param[0] +'="'+ param[1] +'"';
}).join(',');
}
};
});
define('url', function() {
var ports = {
'http:': '80',
'https:': '443'
};
function parse(url) {
var link = document.createElement('a'), port;
link.href = url;
port = link.port == "0" ? ports[link.protocol] : link.port;
return {
href: link.href, // fully-resolved URL
protocol: link.protocol,
host: link.host, // includes port
hostname: link.hostname, // authority without authentication info or port
port: port,
pathname: link.pathname, // path without query string or hash
search: link.search, // A.K.A. query string
hash: link.hash
};
}
return {
parse: parse
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment