mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-03-25 09:05:47 +00:00
first real stab at a project page
This commit is contained in:
parent
689be95ac3
commit
448c40e41c
7 changed files with 711 additions and 28 deletions
|
|
@ -1,19 +1,184 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>batteries for node</title>
|
||||
<script>
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push( ['_setAccount', 'UA-214054-5']
|
||||
, ['_trackPageview']
|
||||
);
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<meta name=viewport content=width=device-width>
|
||||
<title>batteries for node</title>
|
||||
<link rel=stylesheet href=../../style.css>
|
||||
<style>
|
||||
#forkme { position: absolute
|
||||
; top: 0
|
||||
; right: 0
|
||||
}
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
<p align=center>
|
||||
A slightly higher-level library for node<br>
|
||||
<a href="http://github.com/samsonjs/batteries">github project</a>
|
||||
</p>
|
||||
#info { text-align: center
|
||||
; margin: 0 auto
|
||||
; padding: 1em
|
||||
; border: solid 1px #ccc
|
||||
; width: 90%
|
||||
; max-width: 950px
|
||||
; background-color: #fff
|
||||
; border-radius: 20px
|
||||
; -webkit-border-radius: 20px
|
||||
; -moz-border-radius: 20px
|
||||
}
|
||||
|
||||
h4 { margin: 0.5em 0 0.7em }
|
||||
|
||||
#info > div { text-align: center
|
||||
; font-size: 1.3em
|
||||
; width: 32%
|
||||
; max-width: 400px
|
||||
; float: left
|
||||
; padding: 0.5em 0.2em
|
||||
; border-left: dashed 1px #aaa
|
||||
}
|
||||
|
||||
#info > div:first-child { border-left: none }
|
||||
|
||||
#info div:last-child { clear: both
|
||||
; float: none
|
||||
; border: none
|
||||
; height: 0
|
||||
; width: 0
|
||||
; padding: 0
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push( ['_setAccount', 'UA-214054-5']
|
||||
, ['_trackPageview']
|
||||
);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
<script src=../gitter.js></script>
|
||||
<script>
|
||||
(function() {
|
||||
function addClass(el, name) {
|
||||
var c = el.className || name
|
||||
if (!c.match(new RegExp('\b' + name + '\b', 'i'))) c += ' ' + name
|
||||
}
|
||||
function html(id, h) {
|
||||
document.getElementById(id).innerHTML = h
|
||||
}
|
||||
function text(id, text) {
|
||||
document.getElementById(id).innerText = text
|
||||
}
|
||||
function highlight(id) {
|
||||
document.getElementById(id).style.className = ' highlight'
|
||||
}
|
||||
function textHighlight(id, text) {
|
||||
var el = document.getElementById(id)
|
||||
el.innerText = text
|
||||
el.className = ' highlight'
|
||||
}
|
||||
function hide(id) {
|
||||
document.getElementById(id).style.display = 'none'
|
||||
}
|
||||
|
||||
function branchLink(b) {
|
||||
return '<a href=https://github.com/samsonjs/batteries/tree/' + b + '>' + b + '</a>'
|
||||
}
|
||||
|
||||
function userLink(u) {
|
||||
return '<a href=https://github.com/' + u.login + '>' + u.name + '</a>'
|
||||
}
|
||||
|
||||
function langsByUsage(langs) {
|
||||
return Object.keys(langs).sort(function(a, b) {
|
||||
return langs[a] < langs[b] ? -1 : 1
|
||||
})
|
||||
}
|
||||
|
||||
var data = {}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', ready, false)
|
||||
|
||||
function fakeReady() {
|
||||
text('branches', 'master')
|
||||
text('langs', 'JavaScript')
|
||||
}
|
||||
|
||||
function ready() {
|
||||
GITR.repo('samsonjs/batteries')
|
||||
.getBranches(function(err, branches) {
|
||||
if (err) {
|
||||
text('branches', '(oops)')
|
||||
} else {
|
||||
data.branches = branches
|
||||
html('branches', Object.keys(branches).map(branchLink).join('<br>'))
|
||||
}
|
||||
})
|
||||
.getLanguages(function(err, langs) {
|
||||
if (err) {
|
||||
text('(oops)')
|
||||
return
|
||||
}
|
||||
data.langs = langs
|
||||
html('langs', langsByUsage(langs).join('<br>'))
|
||||
})
|
||||
.getWatchers(function(err, users) {
|
||||
if (err) {
|
||||
text('nwatchers', '?')
|
||||
} else {
|
||||
data.watchers = users
|
||||
textHighlight('nwatchers', users.length)
|
||||
if (users.length === 1) hide('wplural')
|
||||
}
|
||||
})
|
||||
.getNetwork(function(err, repos) {
|
||||
if (err) {
|
||||
text('nforks', '?')
|
||||
} else {
|
||||
data.forks = repos
|
||||
textHighlight('nforks', repos.length)
|
||||
if (repos.length === 1) hide('fplural')
|
||||
}
|
||||
})
|
||||
.getContributors(function(err, users) {
|
||||
if (err) {
|
||||
text('contributors', '(oops)')
|
||||
} else {
|
||||
data.contributors = users
|
||||
html('contributors', users.map(userLink).join('<br>'))
|
||||
}
|
||||
})
|
||||
|
||||
//
|
||||
// integrate github finder into project pages
|
||||
//
|
||||
}
|
||||
}())
|
||||
</script>
|
||||
</head>
|
||||
<a class=up href=../../>← samhuri.net</a>
|
||||
<p><a class=up href=../>← projects</a></p>
|
||||
<a href=https://github.com/samsonjs/batteries><img id=forkme src=../forkme.png alt="Fork me on GitHub"></a>
|
||||
<h1>batteries</h1>
|
||||
<h2>useful stuff for node</h2>
|
||||
<table align=center>
|
||||
<tr>
|
||||
<td align=right><span id=nwatchers><img src=../spinner.gif></span> watcher<span id=wplural>s</span></td>
|
||||
<td>—</td>
|
||||
<td align=left><span id=nforks><img src=../spinner.gif></span> fork<span id=fplural>s</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id=info>
|
||||
<div>
|
||||
<h4>branches</h4>
|
||||
<span id=branches><img src=../spinner.gif></span>
|
||||
</div>
|
||||
<div>
|
||||
<h4>languages</h4>
|
||||
<span id=langs><img src=../spinner.gif></span>
|
||||
</div>
|
||||
<div>
|
||||
<h4>contributors</h4>
|
||||
<span id=contributors><img src=../spinner.gif></span>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
BIN
proj/forkme.png
Normal file
BIN
proj/forkme.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
BIN
proj/gh.png
Normal file
BIN
proj/gh.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
425
proj/gitter.js
Normal file
425
proj/gitter.js
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/// gitter
|
||||
/// http://github.com/samsonjs/gitter
|
||||
/// @_sjs
|
||||
///
|
||||
/// Copyright 2010 Sami Samhuri <sami.samhuri@gmail.com>
|
||||
/// MIT License
|
||||
|
||||
// TODO:
|
||||
// - authentication and write APIs
|
||||
|
||||
(function() {
|
||||
var global = this
|
||||
, isBrowser = 'document' in global
|
||||
// when running in the browser request is set later
|
||||
, request = isBrowser ? null : require('request')
|
||||
, Blob, Branch, Commit, Raw, Repo, Tree, User
|
||||
, api
|
||||
|
||||
api = {
|
||||
blob: function(repo, sha, path, cb) {
|
||||
return new Blob(repo, sha, path, cb)
|
||||
},
|
||||
branch: function(repo, branch, cb) {
|
||||
return new Branch(repo, branch, cb)
|
||||
},
|
||||
commits: function(repo, branch, cb) {
|
||||
return new Branch(repo, branch).getCommits(cb)
|
||||
},
|
||||
commit: function(repo, sha, cb) {
|
||||
return new Commit(repo, sha, cb)
|
||||
},
|
||||
raw: function(repo, sha, cb) {
|
||||
return new Raw(repo, sha, cb)
|
||||
},
|
||||
repo: function(repo, cb) {
|
||||
return new Repo(repo, cb)
|
||||
},
|
||||
branches: function(repo, cb) {
|
||||
return new Repo(repo).getBranches(cb)
|
||||
},
|
||||
collaborators: function(repo, cb) {
|
||||
return new Repo(repo).getCollaborators(cb)
|
||||
},
|
||||
contributors: function(repo, cb) {
|
||||
return new Repo(repo).getContributors(cb)
|
||||
},
|
||||
languages: function(repo, cb) {
|
||||
return new Repo(repo).getLanguages(cb)
|
||||
},
|
||||
network: function(repo, cb) {
|
||||
return new Repo(repo).getNetwork(cb)
|
||||
},
|
||||
tags: function(repo, cb) {
|
||||
return new Repo(repo).getTags(cb)
|
||||
},
|
||||
watchers: function(repo, cb) {
|
||||
return new Repo(repo).getWatchers(cb)
|
||||
},
|
||||
tree: function(repo, sha, cb) {
|
||||
return new Tree(repo, sha, cb)
|
||||
},
|
||||
blobs: function(repo, sha, cb) {
|
||||
return new Tree(repo, sha).getBlobs(cb)
|
||||
},
|
||||
user: function(user, cb) {
|
||||
return new User(user, cb)
|
||||
},
|
||||
followers: function(user, cb) {
|
||||
return new User(user).getFollowers(cb)
|
||||
},
|
||||
following: function(user, cb) {
|
||||
return new User(user).getFollowing(cb)
|
||||
},
|
||||
repos: function(user, cb) {
|
||||
return new User(user).getRepos(cb)
|
||||
},
|
||||
watched: function(user, cb) {
|
||||
return new User(user).getWatched(cb)
|
||||
}
|
||||
}
|
||||
if (isBrowser) global.GITR = api
|
||||
else module.exports = api
|
||||
|
||||
|
||||
// Define resources //
|
||||
|
||||
Blob = createResource('blob/show/:repo/:tree/:path', {
|
||||
has: [ ['commits', 'commits/list/:repo/:tree/:path'] ]
|
||||
})
|
||||
Branch = createResource('commits/show/:repo/:branch', {
|
||||
has: [ ['commits', 'commits/list/:repo/:branch'] ]
|
||||
})
|
||||
Commit = createResource('commits/show/:repo/:sha')
|
||||
Raw = createResource('blob/show/:repo/:sha')
|
||||
Repo = createResource('repos/show/:repo', {
|
||||
has: [ 'branches'
|
||||
, 'collaborators'
|
||||
, 'contributors'
|
||||
, 'languages'
|
||||
, 'network'
|
||||
, 'tags'
|
||||
, 'watchers'
|
||||
]
|
||||
})
|
||||
Tree = createResource('tree/show/:repo/:sha', {
|
||||
has: [ ['blobs', 'blob/all/:repo/:sha']
|
||||
, ['fullBlobs', 'blob/full/:repo/:sha']
|
||||
, ['fullTree', 'tree/full/:repo/:sha']
|
||||
]
|
||||
})
|
||||
Tree.prototype._processData = function(data) {
|
||||
Resource.prototype._processData.call(this, data)
|
||||
this.blobs = this.data()
|
||||
}
|
||||
|
||||
User = createResource('user/show/:user', {
|
||||
has: [ 'followers'
|
||||
, 'following'
|
||||
, ['repos', 'repos/show/:user']
|
||||
, ['watched', 'repos/watched/:user']
|
||||
]
|
||||
})
|
||||
|
||||
// Construct a new github resource.
|
||||
//
|
||||
// options:
|
||||
// - params: params for constructor (optional, inferred from route if missing)
|
||||
// - has: list of related resources, accessors are created for each item
|
||||
//
|
||||
// The members of the `has` list are arrays of the form [name, route, unpack].
|
||||
// The first member, name, is used to create an accessor (e.g. getName), and
|
||||
// is required.
|
||||
//
|
||||
// Route and unpack are optional. Route specifies the endpoint for this
|
||||
// resource and defaults to the name appended to the main resource's endpoint.
|
||||
//
|
||||
// Unpack is a function that extracts the desired value from the object fetched
|
||||
// for this resource. It defaults to a function that picks out the only property
|
||||
// from an object, or returns the entire walue if not an object or it contains
|
||||
// more than one property.
|
||||
//
|
||||
// When passing only the name you may pass it directly without wrapping it in
|
||||
// an array.
|
||||
function createResource(route, options) {
|
||||
if (!route) throw new Error('route is required')
|
||||
options = options || {}
|
||||
|
||||
var resource = function() { Resource.apply(this, [].slice.call(arguments)) }
|
||||
inherits(resource, Resource)
|
||||
|
||||
resource.prototype._route = route
|
||||
resource.prototype._params = options.params || paramsFromRoute(route)
|
||||
|
||||
resource.has = function(prop, route, unpack) {
|
||||
unpack = unpack || onlyProp
|
||||
var dataProp = '_' + prop
|
||||
, fn = 'get' + titleCaseFirst(prop)
|
||||
, processData = function(d) {
|
||||
getter(this, dataProp, function() { return camelize(unpack(d))})
|
||||
}
|
||||
, result = function(resource) { return this[dataProp] }
|
||||
resource.prototype[fn] = function(cb, force) {
|
||||
return this._fetch({ prop: dataProp
|
||||
, route: route || this._route + '/' + prop
|
||||
, processData: processData.bind(this)
|
||||
, result: result.bind(this)
|
||||
}, cb.bind(this), force)
|
||||
}
|
||||
return resource
|
||||
}
|
||||
if (options.has) options.has.forEach(function(args) {
|
||||
resource.has.apply(resource, Array.isArray(args) ? args : [args])
|
||||
})
|
||||
|
||||
return resource
|
||||
}
|
||||
|
||||
// Assigns the given resource args to the new instance. Sets the path to the
|
||||
// endpoint for main resource data.
|
||||
//
|
||||
// If the optional last arg is a function main data is fetched immediately,
|
||||
// and that function is used as the callback.
|
||||
//
|
||||
// If the optional last arg is an object then it is set as the main resource
|
||||
// data.
|
||||
function Resource(/* ...args, opt: data or callback */) {
|
||||
var args = [].slice.call(arguments)
|
||||
, last = args[args.length - 1]
|
||||
|
||||
// assign params from args
|
||||
this._params.forEach(function(param, i) {
|
||||
this[param] = args[i]
|
||||
}.bind(this))
|
||||
|
||||
// set the resource path
|
||||
this.urlPath = this.resolve(this._route)
|
||||
|
||||
if (typeof last === 'function') this.fetch(last)
|
||||
else if (typeof last === 'object') this.data(last)
|
||||
}
|
||||
|
||||
// Set or get main data for this resource, or fetch
|
||||
// a specific property from the data.
|
||||
//
|
||||
// When the data param is empty cached data is returned.
|
||||
//
|
||||
// When the data param is a string the property by that name
|
||||
// is looked up in the cached data.
|
||||
//
|
||||
// Otherwise cached data is set to the data param.
|
||||
Resource.prototype.data = function(data) {
|
||||
if (!data) return this._data
|
||||
if (typeof data === 'string' && typeof this._data === 'object') return this._data[data]
|
||||
|
||||
getter(this, '_data', function() { return data }, {configurable: true})
|
||||
return this
|
||||
}
|
||||
|
||||
// Fetch the main data for this resource.
|
||||
//
|
||||
// cb: callback(err, data)
|
||||
// force: if true load data from github, bypassing the local cache
|
||||
Resource.prototype.fetch = function(cb, force) {
|
||||
return this._fetch({ prop: '_data'
|
||||
, route: this.urlPath
|
||||
, processData: this._processData.bind(this)
|
||||
, result: function(resource) { return resource }
|
||||
}, cb.bind(this), force)
|
||||
}
|
||||
|
||||
// 'repos/show/:user/:repo/branches' -> 'repos/show/samsonjs/gitter
|
||||
Resource.prototype.resolve = function(route) { // based on crock's supplant
|
||||
if (route.indexOf(':') < 0) return route
|
||||
return route.replace(/:(\w+)\b/g, function (s, prop) {
|
||||
var val = this[prop]
|
||||
if (typeof val !== 'string' && typeof val !== 'number')
|
||||
throw new Error('no suitable property named "' + prop + '" (found ' + val + ')')
|
||||
return val
|
||||
}.bind(this))
|
||||
}
|
||||
|
||||
// Fetch arbitrary data from github.
|
||||
//
|
||||
// options:
|
||||
// - prop: name of data cache property
|
||||
// - route: route to github endpoint (can contain resource params)
|
||||
// - processData: function that processes fetched data
|
||||
// - result: function to obtain the result passed to the callback
|
||||
// cb: callback(err, data)
|
||||
// force: if true load data from github, bypassing the local cache
|
||||
Resource.prototype._fetch = function(options, cb, force) {
|
||||
if (!force && this[options.prop]) {
|
||||
cb(null, options.result(this))
|
||||
return this
|
||||
}
|
||||
|
||||
// Interpolate resource params
|
||||
var path = this.resolve(options.route)
|
||||
|
||||
// Make the request
|
||||
return this._get(path, function(err, data) {
|
||||
if (err) {
|
||||
cb(err)
|
||||
return
|
||||
}
|
||||
options.processData(data)
|
||||
cb(null, options.result(this))
|
||||
}.bind(this))
|
||||
}
|
||||
|
||||
// Fetch data from github. JSON responses are parsed.
|
||||
//
|
||||
// path: github endpoint
|
||||
// cb: callback(err, data)
|
||||
Resource.prototype._get = function(path, cb) {
|
||||
request({uri: 'http://github.com/api/v2/json/' + path}, function(err, response, body) {
|
||||
if (err)
|
||||
cb(err)
|
||||
else if (isBrowser)
|
||||
cb(null, body) // body is an object
|
||||
else if (response.statusCode !== 200)
|
||||
cb(new Error('failed to fetch ' + path + ': ' + response.statusCode))
|
||||
else if (response.headers['content-type'].match(/json/))
|
||||
cb(null, JSON.parse(body))
|
||||
else
|
||||
cb(null, body)
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
// Descendents of Resource can overwrite _processData and _unpack to process
|
||||
// the main resource data differently.
|
||||
|
||||
Resource.prototype._processData = function(data) {
|
||||
return this.data(camelize(this._unpack(data)))
|
||||
}
|
||||
Resource.prototype._unpack = onlyProp
|
||||
|
||||
|
||||
// Utilities //
|
||||
|
||||
function camel(s) { // created_at => createdAt
|
||||
return s.replace(/_(.)/g, function(_, l) { return l.toUpperCase() })
|
||||
}
|
||||
function camelize(obj) { // camelize all keys of an object, or all objects in an array
|
||||
if (!obj || typeof obj === 'string') return obj
|
||||
if (Array.isArray(obj)) return obj.map(camelize)
|
||||
return Object.keys(obj).reduce(function(newObj, k) {
|
||||
newObj[camel(k)] = obj[k]
|
||||
return newObj
|
||||
}, {})
|
||||
}
|
||||
|
||||
function getter(obj, prop, fn, opts) { // minor convenience
|
||||
opts = opts || {}
|
||||
opts.get = fn
|
||||
Object.defineProperty(obj, prop, opts)
|
||||
}
|
||||
|
||||
// util.inherits from node
|
||||
function inherits(ctor, superCtor) {
|
||||
ctor.super_ = superCtor
|
||||
ctor.prototype = Object.create(superCtor.prototype, {
|
||||
constructor: {
|
||||
value: ctor,
|
||||
enumerable: false
|
||||
}
|
||||
})
|
||||
}
|
||||
// get an only property, if any
|
||||
function onlyProp(obj) {
|
||||
if (obj && typeof obj === 'object') {
|
||||
var keys = Object.keys(obj)
|
||||
if (keys.length === 1) return obj[keys[0]]
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// 'repos/show/:user/:repo/branches' -> ['user', 'repo']
|
||||
function paramsFromRoute(route) {
|
||||
if (route.indexOf(':') === -1) return []
|
||||
return route.split('/')
|
||||
.filter(function(s) { return s.charAt(0) === ':' })
|
||||
.map(function(s) { return s.slice(1) })
|
||||
}
|
||||
|
||||
function titleCaseFirst(s) { return s.charAt(0).toUpperCase() + s.slice(1) }
|
||||
|
||||
|
||||
// Browser Utilities //
|
||||
|
||||
if (isBrowser) (function() {
|
||||
var update, merge, load, _jsonpCounter = 1
|
||||
request = function(options, cb) { // jsonp request, quacks like mikeal's request module
|
||||
var jsonpCallbackName = '_jsonpCallback' + _jsonpCounter++
|
||||
, url = options.uri + '?callback=GITR.' + jsonpCallbackName
|
||||
GITR[jsonpCallbackName] = function(obj) {
|
||||
cb(null, null, obj)
|
||||
setTimeout(function() { delete GITR[jsonpCallbackName] }, 0)
|
||||
}
|
||||
load(url)
|
||||
}
|
||||
|
||||
// bind from Prototype (for Safari 5)
|
||||
if (!Function.prototype.bind) {
|
||||
update = function(array, args) {
|
||||
var arrayLength = array.length, length = args.length
|
||||
while (length--) array[arrayLength + length] = args[length]
|
||||
return array
|
||||
}
|
||||
merge = function(array, args) {
|
||||
array = [].slice.call(array, 0)
|
||||
return update(array, args)
|
||||
}
|
||||
Function.prototype.bind = function(context) {
|
||||
if (arguments.length < 2 && typeof arguments[0] === 'undefined') return this
|
||||
var __method = this, args = [].slice.call(arguments, 1)
|
||||
return function() {
|
||||
var a = merge(args, arguments)
|
||||
return __method.apply(context, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
// bootstrap loader from LABjs
|
||||
load = function(url) {
|
||||
var oDOC = document
|
||||
, handler
|
||||
, head = oDOC.head || oDOC.getElementsByTagName("head")
|
||||
|
||||
// loading code borrowed directly from LABjs itself
|
||||
// (now removes script elem when done and nullifies its reference --sjs)
|
||||
setTimeout(function () {
|
||||
if ("item" in head) { // check if ref is still a live node list
|
||||
if (!head[0]) { // append_to node not yet ready
|
||||
setTimeout(arguments.callee, 25)
|
||||
return
|
||||
}
|
||||
head = head[0]; // reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
|
||||
}
|
||||
var scriptElem = oDOC.createElement("script"),
|
||||
scriptdone = false
|
||||
scriptElem.onload = scriptElem.onreadystatechange = function () {
|
||||
if ((scriptElem.readyState && scriptElem.readyState !== "complete" && scriptElem.readyState !== "loaded") || scriptdone) {
|
||||
return false
|
||||
}
|
||||
scriptElem.onload = scriptElem.onreadystatechange = null
|
||||
scriptElem.parentNode.removeChild(scriptElem)
|
||||
scriptElem = null
|
||||
scriptdone = true
|
||||
};
|
||||
scriptElem.src = url
|
||||
head.insertBefore(scriptElem, head.firstChild)
|
||||
}, 0)
|
||||
|
||||
// required: shim for FF <= 3.5 not having document.readyState
|
||||
if (oDOC.readyState == null && oDOC.addEventListener) {
|
||||
oDOC.readyState = "loading"
|
||||
oDOC.addEventListener("DOMContentLoaded", function handler() {
|
||||
oDOC.removeEventListener("DOMContentLoaded", handler, false)
|
||||
oDOC.readyState = "complete"
|
||||
}, false)
|
||||
}
|
||||
}
|
||||
}())
|
||||
}())
|
||||
|
|
@ -4,6 +4,16 @@
|
|||
<meta name=viewport content=width=device-width>
|
||||
<title>samhuri.net</title>
|
||||
<link rel=stylesheet href=../style.css>
|
||||
<style>
|
||||
#forkme { position: absolute
|
||||
; top: 0
|
||||
; right: 0
|
||||
}
|
||||
|
||||
#gh { text-align: center }
|
||||
|
||||
span { padding: 5px }
|
||||
</style>
|
||||
<script>
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push( ['_setAccount', 'UA-214054-5']
|
||||
|
|
@ -16,8 +26,53 @@
|
|||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
<script src=gitter.js></script>
|
||||
<script>
|
||||
(function() {
|
||||
function addClass(el, name) {
|
||||
var c = el.className || name
|
||||
if (!c.match(new RegExp('\b' + name + '\b', 'i'))) c += ' ' + name
|
||||
}
|
||||
function text(id, text) {
|
||||
document.getElementById(id).innerText = text
|
||||
}
|
||||
function highlight(id) {
|
||||
document.getElementById(id).style.className = ' highlight'
|
||||
}
|
||||
function textHighlight(id, text) {
|
||||
var el = document.getElementById(id)
|
||||
el.innerText = text
|
||||
el.className = ' highlight'
|
||||
}
|
||||
|
||||
var data = {}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', ready, false)
|
||||
|
||||
function fakeReady() {
|
||||
textHighlight('nrepos', '20')
|
||||
textHighlight('nfollowers', '13')
|
||||
textHighlight('nwatched', '100')
|
||||
textHighlight('nfollowing', '69')
|
||||
}
|
||||
|
||||
function ready() {
|
||||
['followers', 'following', 'repos', 'watched'].forEach(function(thing) {
|
||||
GITR[thing]('samsonjs', function(err, things) {
|
||||
if (err) {
|
||||
text('n' + thing, '?')
|
||||
} else {
|
||||
data[thing] = things
|
||||
textHighlight('n' + thing, things.length)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}())
|
||||
</script>
|
||||
</head>
|
||||
<a class=up href=../>← samhuri.net</a>
|
||||
<a href=https://github.com/samsonjs><img id=forkme src=forkme.png alt="Fork me on GitHub"></a>
|
||||
<h1>projects</h1>
|
||||
<ul>
|
||||
<li><a href=batteries>batteries</a></li>
|
||||
|
|
@ -26,6 +81,21 @@
|
|||
<li><a href=repl-edit>repl-edit</a></li>
|
||||
<li><a href=strftime>strftime</a></li>
|
||||
</ul>
|
||||
<p id=gh>
|
||||
<a class=img href=https://github.com/samsonjs><img src=gh.png alt=GitHub></a>
|
||||
</p>
|
||||
<table align=center>
|
||||
<tr>
|
||||
<td align=right><span id=nrepos><img src=spinner.gif></span> projects</td>
|
||||
<td>—</td>
|
||||
<td align=left><span id=nfollowers><img src=spinner.gif></span> followers</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align=right>watching <span id=nwatched><img src=spinner.gif></span> projects
|
||||
<td>—</td>
|
||||
<td align=left>following <span id=nfollowing><img src=spinner.gif></span> people</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p id=promoteJS>
|
||||
<a class=img href=https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function title='JS Function arity'><img src=http://static.jsconf.us/promotejsh.gif height=150 width=180 alt='JS Function arity'/></a>
|
||||
</p>
|
||||
|
|
|
|||
BIN
proj/spinner.gif
Normal file
BIN
proj/spinner.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
45
style.css
45
style.css
|
|
@ -4,13 +4,20 @@ body { background-color: #f7f7f7
|
|||
}
|
||||
|
||||
h1 { text-align: center
|
||||
; vertical-align: center
|
||||
; font-size: 4em
|
||||
; font-weight: normal
|
||||
; height: 100%
|
||||
; margin: 0.6em 0 0.4em
|
||||
; padding: 0
|
||||
}
|
||||
; vertical-align: center
|
||||
; font-size: 4em
|
||||
; font-weight: normal
|
||||
; margin: 0.6em 0 0.4em
|
||||
; padding: 0
|
||||
}
|
||||
|
||||
h2 { text-align: center
|
||||
; vertical-align: center
|
||||
; font-size: 2em
|
||||
; font-weight: normal
|
||||
; margin: 0.2em 0 1em
|
||||
; padding: 0
|
||||
}
|
||||
|
||||
ul { text-align: center
|
||||
; margin: 0 auto
|
||||
|
|
@ -24,6 +31,11 @@ ul { text-align: center
|
|||
; -moz-border-radius: 20px
|
||||
}
|
||||
|
||||
a { color: #22a
|
||||
; text-decoration: none
|
||||
; border-bottom: dashed 1px #22a
|
||||
}
|
||||
|
||||
li { display: inline
|
||||
; font-size: 2em
|
||||
; margin: 0
|
||||
|
|
@ -32,13 +44,12 @@ li { display: inline
|
|||
li:after { content: ' •' }
|
||||
li:last-child:after { content: '' }
|
||||
|
||||
li a { color: #22a
|
||||
; text-decoration: none
|
||||
; border-bottom: dashed 1px #22a
|
||||
; padding: 5px
|
||||
li a { padding: 5px
|
||||
; text-shadow: #999 5px 5px 5px
|
||||
}
|
||||
li a:visited { color: #227 }
|
||||
|
||||
li a:hover,
|
||||
li a:active { color: #000
|
||||
; text-shadow: #aa7 5px 5px 5px
|
||||
; border-bottom: dashed 1px #000
|
||||
|
|
@ -57,6 +68,18 @@ p#promoteJS { margin-top: 3em
|
|||
; text-align: center
|
||||
}
|
||||
|
||||
td { font-size: 1.5em
|
||||
; line-height: 1.6em
|
||||
}
|
||||
|
||||
td:nth-child(2) { padding: 0 10px }
|
||||
|
||||
|
||||
.highlight { background-image: -webkit-gradient(radial, 50% 50%, 5, 50% 50%, 15, from(#ffa), to(#f7f7f7))
|
||||
; background-image: -moz-radial-gradient(center 45deg, circle contain, #ffa 0%, #f7f7f7 100%)
|
||||
; font-size: 1.2em
|
||||
}
|
||||
|
||||
|
||||
/* iPad (landscape) */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue