Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

got most of it working

  • Loading branch information...
commit 2a4f914642377e3041a2e26b1f88a7a19db32cd1 1 parent 9c41fc7
@jgallen23 jgallen23 authored
View
1  .gitignore
@@ -0,0 +1 @@
+node_modules
View
22 Makefile
@@ -0,0 +1,22 @@
+SRC = $(shell find lib -type f)
+
+all: dist/hubinfo.js
+
+dist/hubinfo.js: $(SRC)
+ @./support/template.js lib/templates/default.html > template.js
+ @./node_modules/.bin/masher masher.json
+ cp -r lib/images dist/
+ rm template.js
+
+
+install:
+ npm install masher
+ npm install stylus
+
+clean:
+ rm -rf dist
+
+preview:
+ @python -m SimpleHTTPServer 8001
+
+.PHONY: install clean preview
View
1  dist/hubinfo.css
@@ -0,0 +1 @@
+.github-repo{font-size:14px;font-family:Helvetica,Arial,sans-serif;letter-spacing:1px;border-radius:5px;border:1px solid #ccc;box-shadow:0 0 3px #333;background:url("images/Octocat.png") no-repeat right bottom}.github-repo a{text-decoration:none}.github-repo a:hover{text-decoration:underline}.github-repo .repo-header{padding:5px 10px;background:rgba(240,240,240,0.70)}.github-repo .repo-header .repo-stats{font-size:12px;float:right}.github-repo .repo-header .repo-stats span,.github-repo .repo-header .repo-stats a{padding-right:5px;padding:0 5px 0 25px;color:#000}.github-repo .repo-header .repo-stats .repo-watchers{background:url("images/repostat.png") no-repeat;background-position:5px -5px}.github-repo .repo-header .repo-stats .repo-forks{background:url("images/repostat.png") no-repeat;background-position:5px -55px}.github-repo .repo-header .repo-name{font-size:18px;letter-spacing:2px;display:block}.github-repo .repo-commit{padding:5px 10px}.github-repo .repo-commit .repo-commit-message{color:#000}.github-repo .repo-commit .repo-commit-date{display:block;letter-spacing:0;font-style:italic;font-size:12px;color:#333}
View
1  dist/hubinfo.js
@@ -0,0 +1 @@
+(function(a){(function(){var a={};this.tmpl=function b(c,d){var e=/\W/.test(c)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+c.replace(/[\r\t\n]/g," ").split("{!").join(" ").replace(/((^|!})[^\t]*)'/g,"$1\r").replace(/\t=(.*?)!}/g,"',$1,'").split(" ").join("');").split("!}").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):a[c]=a[c]||b(document.getElementById(c).innerHTML);return d?e(d):e}})();var b=function(b,c,d){a.ajax({url:"https://api.github.com/repos/"+b+"/"+c,dataType:"jsonp",success:function(a){if(a.data.message=="Not Found")throw new Error("Invalid user or repo");d(a.data)}})},c=function(b,c,d){a.ajax({url:"http://github.com/api/v2/json/commits/list/"+b+"/"+c+"/master",dataType:"jsonp",success:function(a){var b=a.commits[0];d(b)}})},d=function(a,d,e){var f=0,g=2,h={},i=function(){f==g&&e(h)};b(a,d,function(a){f++,h.project=a,i()}),c(a,d,function(a){f++,h.commit=a,i()})},e=function(a){if(typeof a=="string"){var b=a.split("T")[0].split("-");a=new Date(b[0],b[1]-1,b[2])}var c=(new Date).getTime(),d=c-a.getTime(),e=d/1e3,f=Math.floor(d/864e5);return f===0?"today":f>30?Math.floor(f/30)+" month(s) ago":f+" day(s) ago"};a.fn.hubInfo=function(b){var c=a.extend({},a.fn.hubInfo.defaults,b),f=this;return d(c.user,c.repo,function(b){c.debug&&console.log(b),b.relativeDate=e;var d=tmpl(c.template,b);f.each(function(b,c){var e=a(c);e.html(d)})}),f},a.fn.hubInfo.defaults={user:"",repo:"",debug:!1,template:""}})(jQuery),jQuery.fn.hubInfo.defaults.template='<div class="github-repo"><div class="repo-header"><div class="repo-stats"><span class="repo-lang">{!= project.language !}</span><a href="{!= project.html_url !}" class="repo-watchers">{!= project.watchers !}</a><a href="{!= project.html_url !}" class="repo-forks">{!= project.forks !}</a></div><div><a href="{!= project.html_url !}" class="repo-name">{!= project.name !}</a></div></div><div class="repo-commit"><a class="repo-commit-message" href="http://github.com{!= commit.url !}">{!= commit.message !}</a><div class="repo-commit-date">committed {!= relativeDate(commit.committed_date) !}</div></div></div>'
View
BIN  dist/images/Octocat.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  dist/images/repostat.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
19 example/index.html
@@ -0,0 +1,19 @@
+<html>
+ <head>
+ <title></title>
+ <link rel='stylesheet' type='text/css' href='../dist/hubinfo.css'/>
+ <script src="live.js"></script>
+ </head>
+ <body>
+
+ <div id='hubinfo'></div>
+ <script src='jquery.js'></script>
+ <script src='../dist/hubinfo.js'></script>
+ <script>
+ $('#hubinfo').hubInfo({
+ user: 'jgallen23',
+ repo: 'hubinfo'
+ });
+ </script>
+ </body>
+</html>
View
9,266 example/jquery.js
9,266 additions, 0 deletions not shown
View
233 example/live.js
@@ -0,0 +1,233 @@
+/*
+ Live.js - One script closer to Designing in the Browser
+ Written for Handcraft.com by Martin Kool (@mrtnkl).
+
+ Version 4.
+ Recent change: Made stylesheet and mimetype checks case insensitive.
+
+ http://livejs.com
+ http://livejs.com/license (MIT)
+ @livejs
+
+ Include live.js#css to monitor css changes only.
+ Include live.js#js to monitor js changes only.
+ Include live.js#html to monitor html changes only.
+ Mix and match to monitor a preferred combination such as live.js#html,css
+
+ By default, just include live.js to monitor all css, js and html changes.
+
+ Live.js can also be loaded as a bookmarklet. It is best to only use it for CSS then,
+ as a page reload due to a change in html or css would not re-include the bookmarklet.
+ To monitor CSS and be notified that it has loaded, include it as: live.js#css,notify
+*/
+(function () {
+
+ var headers = { "Etag": 1, "Last-Modified": 1, "Content-Length": 1, "Content-Type": 1 },
+ resources = {},
+ pendingRequests = {},
+ currentLinkElements = {},
+ oldLinkElements = {},
+ interval = 1000,
+ loaded = false,
+ active = { "html": 1, "css": 1, "js": 1 };
+
+ var Live = {
+
+ // performs a cycle per interval
+ heartbeat: function () {
+ if (document.body) {
+ // make sure all resources are loaded on first activation
+ if (!loaded) Live.loadresources();
+ Live.checkForChanges();
+ }
+ setTimeout(Live.heartbeat, interval);
+ },
+
+ // loads all local css and js resources upon first activation
+ loadresources: function () {
+
+ // helper method to assert if a given url is local
+ function isLocal(url) {
+ var loc = document.location,
+ reg = new RegExp("^\\.|^\/(?!\/)|^[\\w]((?!://).)*$|" + loc.protocol + "//" + loc.host);
+ return url.match(reg);
+ }
+
+ // gather all resources
+ var scripts = document.getElementsByTagName("script"),
+ links = document.getElementsByTagName("link"),
+ uris = [];
+
+ // track local js urls
+ for (var i = 0; i < scripts.length; i++) {
+ var script = scripts[i], src = script.getAttribute("src");
+ if (src && isLocal(src))
+ uris.push(src);
+ if (src && src.match(/\blive.js#/)) {
+ for (var type in active)
+ active[type] = src.match("[#,|]" + type) != null
+ if (src.match("notify"))
+ alert("Live.js is loaded.");
+ }
+ }
+ if (!active.js) uris = [];
+ if (active.html) uris.push(document.location.href);
+
+ // track local css urls
+ for (var i = 0; i < links.length && active.css; i++) {
+ var link = links[i], rel = link.getAttribute("rel"), href = link.getAttribute("href", 2);
+ if (href && rel && rel.match(new RegExp("stylesheet", "i")) && isLocal(href)) {
+ uris.push(href);
+ currentLinkElements[href] = link;
+ }
+ }
+
+ // initialize the resources info
+ for (var i = 0; i < uris.length; i++) {
+ var url = uris[i];
+ Live.getHead(url, function (url, info) {
+ resources[url] = info;
+ });
+ }
+
+ // add rule for morphing between old and new css files
+ var head = document.getElementsByTagName("head")[0],
+ style = document.createElement("style"),
+ rule = "transition: all .3s ease-out;"
+ css = [".livejs-loading * { ", rule, " -webkit-", rule, "-moz-", rule, "-o-", rule, "}"].join('');
+ style.setAttribute("type", "text/css");
+ head.appendChild(style);
+ style.styleSheet ? style.styleSheet.cssText = css : style.appendChild(document.createTextNode(css));
+
+ // yep
+ loaded = true;
+ },
+
+ // check all tracking resources for changes
+ checkForChanges: function () {
+ for (var url in resources) {
+ if (pendingRequests[url])
+ continue;
+
+ Live.getHead(url, function (url, newInfo) {
+ var oldInfo = resources[url],
+ hasChanged = false;
+ resources[url] = newInfo;
+ for (var header in oldInfo) {
+ // do verification based on the header type
+ var oldValue = oldInfo[header],
+ newValue = newInfo[header],
+ contentType = newInfo["Content-Type"];
+ switch (header.toLowerCase()) {
+ case "etag":
+ if (!newValue) break;
+ // fall through to default
+ default:
+ hasChanged = oldValue != newValue;
+ break;
+ }
+ // if changed, act
+ if (hasChanged) {
+ Live.refreshResource(url, contentType);
+ break;
+ }
+ }
+ });
+ }
+ },
+
+ // act upon a changed url of certain content type
+ refreshResource: function (url, type) {
+ switch (type.toLowerCase()) {
+ // css files can be reloaded dynamically by replacing the link element
+ case "text/css":
+ var link = currentLinkElements[url],
+ html = document.body.parentNode,
+ head = link.parentNode,
+ next = link.nextSibling,
+ newLink = document.createElement("link");
+
+ html.className = html.className.replace(/\s*livejs\-loading/gi, '') + ' livejs-loading';
+ newLink.setAttribute("type", "text/css");
+ newLink.setAttribute("rel", "stylesheet");
+ newLink.setAttribute("href", url + "?now=" + new Date() * 1);
+ next ? head.insertBefore(newLink, next) : head.appendChild(newLink);
+ currentLinkElements[url] = newLink;
+ oldLinkElements[url] = link;
+
+ // schedule removal of the old link
+ Live.removeoldLinkElements();
+ break;
+
+ // check if an html resource is our current url, then reload
+ case "text/html":
+ if (url != document.location.href)
+ return;
+
+ // local javascript changes cause a reload as well
+ case "text/javascript":
+ case "application/javascript":
+ case "application/x-javascript":
+ document.location.reload();
+ }
+ },
+
+ // removes the old stylesheet rules only once the new one has finished loading
+ removeoldLinkElements: function () {
+ var pending = 0;
+ for (var url in oldLinkElements) {
+ // if this sheet has any cssRules, delete the old link
+ try {
+ var link = currentLinkElements[url],
+ oldLink = oldLinkElements[url],
+ html = document.body.parentNode,
+ sheet = link.sheet || link.styleSheet,
+ rules = sheet.rules || sheet.cssRules;
+ if (rules.length >= 0) {
+ oldLink.parentNode.removeChild(oldLink);
+ delete oldLinkElements[url];
+ setTimeout(function () {
+ html.className = html.className.replace(/\s*livejs\-loading/gi, '');
+ }, 100);
+ }
+ } catch (e) {
+ pending++;
+ }
+ if (pending) setTimeout(Live.removeoldLinkElements, 50);
+ }
+ },
+
+ // performs a HEAD request and passes the header info to the given callback
+ getHead: function (url, callback) {
+ pendingRequests[url] = true;
+ var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XmlHttp");
+ xhr.open("HEAD", url, true);
+ xhr.onreadystatechange = function () {
+ delete pendingRequests[url];
+ if (xhr.readyState == 4 && xhr.status != 304) {
+ xhr.getAllResponseHeaders();
+ var info = {};
+ for (var h in headers) {
+ var value = xhr.getResponseHeader(h);
+ // adjust the simple Etag variant to match on its significant part
+ if (h.toLowerCase() == "etag" && value) value = value.replace(/^W\//, '');
+ if (h.toLowerCase() == "content-type" && value) value = value.replace(/^(.*?);.*?$/i, "$1");
+ info[h] = value;
+ }
+ callback(url, info);
+ }
+ }
+ xhr.send();
+ }
+ };
+
+ // start listening
+ if (document.location.protocol != "file:") {
+ if (!window.liveJsLoaded)
+ Live.heartbeat();
+
+ window.liveJsLoaded = true;
+ }
+ else if (window.console)
+ console.log("Live.js doesn't support the file protocol. It needs http.");
+})();
View
BIN  lib/images/Octocat.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  lib/images/repostat.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
7 lib/scripts/copyright.js
@@ -0,0 +1,7 @@
+/*!
+ * hubInfo - a github repo widget
+ * v0.0.1
+ * https://github.com/jgallen23/hubinfo
+ * copyright JGA 2012
+ * MIT License
+ */
View
122 lib/scripts/hubinfo.js
@@ -0,0 +1,122 @@
+(function($) {
+ // Simple JavaScript Templating
+ // John Resig - http://ejohn.org/ - MIT Licensed
+ (function(){
+ var cache = {};
+ this.tmpl = function tmpl(str, data){
+ // Figure out if we're getting a template, or if we need to
+ // load the template - and be sure to cache the result.
+ var fn = !/\W/.test(str) ?
+ cache[str] = cache[str] ||
+ tmpl(document.getElementById(str).innerHTML) :
+
+ // Generate a reusable function that will serve as a template
+ // generator (and which will be cached).
+ new Function("obj",
+ "var p=[],print=function(){p.push.apply(p,arguments);};" +
+
+ // Introduce the data as local variables using with(){}
+ "with(obj){p.push('" +
+
+ // Convert the template into pure JavaScript
+ str
+ .replace(/[\r\t\n]/g, " ")
+ .split("{!").join("\t")
+ .replace(/((^|!})[^\t]*)'/g, "$1\r")
+ .replace(/\t=(.*?)!}/g, "',$1,'")
+ .split("\t").join("');")
+ .split("!}").join("p.push('")
+ .split("\r").join("\\'")
+ + "');}return p.join('');");
+
+ // Provide some basic currying to the user
+ return data ? fn( data ) : fn;
+ };
+ })();
+
+ var getProjectInfo = function(user, repo, cb) {
+ $.ajax({
+ url: 'https://api.github.com/repos/'+user+'/'+repo,
+ dataType: 'jsonp',
+ success: function(res) {
+ if (res.data.message == 'Not Found')
+ throw new Error('Invalid user or repo');
+ cb(res.data);
+ }
+ });
+ };
+
+ var getLastCommit = function(user, repo, cb) {
+ $.ajax({
+ url: 'http://github.com/api/v2/json/commits/list/'+user+'/'+repo+'/master',
+ dataType: 'jsonp',
+ success: function(json) {
+ var latest = json.commits[0];
+ cb(latest);
+ }
+ });
+ };
+
+ var fetchData = function(user, repo, cb) {
+ var count = 0;
+ var total = 2;
+ var data = {};
+ var check = function() {
+ if (count == total)
+ cb(data);
+ };
+ getProjectInfo(user, repo, function(project) {
+ count++;
+ data.project = project;
+ check();
+ });
+ getLastCommit(user, repo, function(commit) {
+ count++;
+ data.commit = commit;
+ check();
+ });
+ };
+
+ var relativeDate = function(date) {
+ if (typeof date === 'string') {
+ var d = date.split('T')[0].split('-');
+ date = new Date(d[0], d[1]-1, d[2]);
+ }
+ var today = new Date().getTime();
+ var diff = today - date.getTime();
+ var seconds = diff / 1000;
+ var days = Math.floor(diff / (1000 * 60 * 60 * 24));
+ if (days === 0) {
+ return 'today';
+ } else if (days > 30) {
+ return Math.floor(days / 30) + ' month(s) ago';
+ }
+ return days + ' day(s) ago';
+ };
+
+ $.fn.hubInfo = function(options) {
+ var opts = $.extend({}, $.fn.hubInfo.defaults, options);
+ var self = this;
+
+ fetchData(opts.user, opts.repo, function(data) {
+ if (opts.debug)
+ console.log(data);
+ data.relativeDate = relativeDate;
+
+ var template = tmpl(opts.template, data);
+ self.each(function(i, item) {
+ var el = $(item);
+ el.html(template);
+
+ });
+ });
+ return self;
+ };
+
+ $.fn.hubInfo.defaults = {
+ user: '',
+ repo: '',
+ debug: false,
+ template: ''
+ };
+})(jQuery);
View
48 lib/styles/hubinfo.styl
@@ -0,0 +1,48 @@
+border-color = #ccc
+background-color = rgba(240,240,240,0.7)
+.github-repo
+ font-size 14px
+ font-family: Helvetica, Arial, sans-serif
+ letter-spacing 1px
+ border-radius 5px
+ border 1px solid border-color
+ box-shadow 0px 0px 3px #333
+ background url(images/Octocat.png) no-repeat right bottom
+ a
+ text-decoration none
+ &:hover
+ text-decoration underline
+ .repo-header
+ padding 5px 10px
+ background background-color
+
+ .repo-stats
+ font-size 12px
+ float right
+ span
+ a
+ padding-right 5px
+ padding 0 5px 0 25px
+ color #000
+ .repo-watchers
+ background url(images/repostat.png) no-repeat
+ background-position 5px -5px
+ .repo-forks
+ background url(images/repostat.png) no-repeat
+ background-position 5px -55px
+
+ .repo-name
+ font-size 18px
+ letter-spacing 2px
+ display block
+
+ .repo-commit
+ padding 5px 10px
+ .repo-commit-message
+ color #000
+ .repo-commit-date
+ display block
+ letter-spacing 0
+ font-style italic
+ font-size 12px
+ color #333
View
16 lib/templates/default.html
@@ -0,0 +1,16 @@
+<div class="github-repo">
+ <div class="repo-header">
+ <div class="repo-stats">
+ <span class="repo-lang">{!= project.language !}</span>
+ <a href="{!= project.html_url !}" class="repo-watchers">{!= project.watchers !}</a>
+ <a href="{!= project.html_url !}" class="repo-forks">{!= project.forks !}</a>
+ </div>
+ <div>
+ <a href="{!= project.html_url !}" class="repo-name">{!= project.name !}</a>
+ </div>
+ </div>
+ <div class="repo-commit">
+ <a class="repo-commit-message" href="http://github.com{!= commit.url !}">{!= commit.message !}</a>
+ <div class="repo-commit-date">committed {!= relativeDate(commit.committed_date) !}</div>
+ </div>
+</div>
View
23 masher.json
@@ -0,0 +1,23 @@
+{
+ "assetPath": "lib",
+ "outputPath": "dist",
+ "groups": {
+ "hubinfo": {
+ "styles": [
+ "styles/hubinfo.styl"
+ ],
+ "scripts": [
+ "scripts/copyright.js",
+ "scripts/hubinfo.js",
+ "../template.js"
+ ]
+ }
+ },
+ "plugins": {
+ "pre": [
+ "stylus"
+ ],
+ "post": [
+ ]
+ }
+}
View
17 support/template.js
@@ -0,0 +1,17 @@
+#!/usr/bin/env node
+
+var fs = require('fs');
+
+var template = process.argv[2];
+
+fs.readFile(template, 'utf8', function(err, str) {
+ if (err) throw err;
+
+ var s = str.split('\n');
+ for (var i = 0, c = s.length; i < c; i++) {
+ s[i] = s[i].replace(/^\s+/, '');
+ }
+ var tmpl = "jQuery.fn.hubInfo.defaults.template = '" + s.join('') + "'";
+ console.log(tmpl);
+});
+
Please sign in to comment.
Something went wrong with that request. Please try again.