├── cnm.bat ├── index.html ├── README.markdown └── js ├── github.commits.widget.js ├── md5.js ├── github.commits.widget-min.js └── github.js /cnm.bat: -------------------------------------------------------------------------------- 1 | echo off 2 | echo Combining and minifying .js files... 3 | 4 | cd ./js/ 5 | "D:\Program Files\SmallSharpTools\Packer for .NET\bin\Packer.exe" -o github.commits.widget-min.js -m combine github.js md5.js github.commits.widget.js 6 | "D:\Program Files\SmallSharpTools\Packer for .NET\bin\Packer.exe" -o github.commits.widget-min.js -m jsmin github.commits.widget-min.js -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | github.commits.widget example 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 33 | 34 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | github.commits.widget javascript 2 | ================================ 3 | 4 | Overview 5 | -------- 6 | This is a very simple to use widget that perfect for open source projects sites. On open source project site you tipically want's to show how active is your development is. Namely, how many commits your project have.. how offten are they. 7 | 8 | How to use 9 | ---------- 10 | Reference 'github.commits.widget-min.js' and containter div and place such script. 11 | 12 | 18 | 19 | where, user is your github account, repo is name of repository and branch is the name of branch you want to track. 20 | 21 | What I got? 22 | ----------- 23 | It will be rendered to html widget containing information about last commits to repository. See index.html. 24 | 25 | Configuration 26 | ------------- 27 | You might limit number commits shown in widget by providing with 'last' parameter: 28 | 34 | 35 | You might also limit the length of commit message, by 'limitMessageTo' parameter: 36 | 42 | 43 | 3rd parties 44 | ----------- 45 | For github.commits.widget I've used: 46 | 47 | * 48 | * 49 | * 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /js/github.commits.widget.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | function widget(element, options, callback) { 3 | this.element = element; 4 | this.options = options; 5 | this.callback = $.isFunction(callback) ? callback : $.noop; 6 | } 7 | 8 | widget.prototype = (function() { 9 | 10 | function _widgetRun(widget) { 11 | if (!widget.options) { 12 | widget.element.append('Options for widget are not set.'); 13 | return; 14 | } 15 | var callback = widget.callback; 16 | var element = widget.element; 17 | var user = widget.options.user; 18 | var repo = widget.options.repo; 19 | var branch = widget.options.branch; 20 | var avatarSize = widget.options.avatarSize || 20; 21 | var last = widget.options.last == undefined ? 0 : widget.options.last; 22 | var limitMessage = widget.options.limitMessageTo == undefined ? 0 : widget.options.limitMessageTo; 23 | 24 | element.append('

Widget intitalization, please wait...

'); 25 | gh.commit.forBranch(user, repo, branch, function (data) { 26 | var commits = data.commits; 27 | var totalCommits = (last < commits.length ? last : commits.length); 28 | 29 | element.empty(); 30 | var list = $('
    ').appendTo(element); 31 | 32 | for (var c = 0; c < totalCommits; c++) { 33 | list.append( 34 | '
  • ' + 35 | ' ' + avatar(commits[c].author.email, avatarSize) + 36 | ' ' + author(commits[c].author.login) + 37 | ' committed ' + message(commits[c].message, commits[c].url) + 38 | ' ' + when(commits[c].committed_date) + 39 | '
  • '); 40 | } 41 | element.append('
    by github.commits.widget
    '); 42 | callback(element); 43 | 44 | function avatar(email, size) { 45 | var emailHash = hex_md5(email); 46 | return ''; 47 | } 48 | 49 | function author(login) { 50 | return '' + login + ''; 51 | } 52 | 53 | function message(commitMessage, url) { 54 | if (limitMessage > 0 && commitMessage.length > limitMessage) 55 | { 56 | commitMessage = commitMessage.substr(0, limitMessage) + '...'; 57 | } 58 | return '"' + '' + commitMessage + '"'; 59 | } 60 | 61 | function when(commitDate) { 62 | var commitTime = new Date(commitDate).getTime(); 63 | var todayTime = new Date().getTime(); 64 | 65 | var differenceInDays = Math.floor(((todayTime - commitTime)/(24*3600*1000))); 66 | if (differenceInDays == 0) { 67 | var differenceInHours = Math.floor(((todayTime - commitTime)/(3600*1000))); 68 | if (differenceInHours == 0) { 69 | var differenceInMinutes = Math.floor(((todayTime - commitTime)/(600*1000))); 70 | if (differenceInMinutes == 0) { 71 | 72 | return 'just now'; 73 | } 74 | 75 | return 'about ' + differenceInMinutes + ' minutes ago'; 76 | } 77 | 78 | return 'about ' + differenceInHours + ' hours ago'; 79 | } 80 | 81 | return differenceInDays + ' days ago'; 82 | } 83 | }); 84 | } 85 | 86 | return { 87 | run: function () { 88 | _widgetRun(this); 89 | } 90 | }; 91 | 92 | })(); 93 | 94 | $.fn.githubInfoWidget = function(options, callback) { 95 | var w = new widget(this, options, callback); 96 | w.run(); 97 | 98 | return this; 99 | } 100 | 101 | })(jQuery); -------------------------------------------------------------------------------- /js/md5.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 3 | * Digest Algorithm, as defined in RFC 1321. 4 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for more info. 8 | */ 9 | 10 | /* 11 | * Configurable variables. You may need to tweak these to be compatible with 12 | * the server-side, but the defaults work in most cases. 13 | */ 14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ 16 | 17 | /* 18 | * These are the functions you'll usually want to call 19 | * They take string arguments and return either hex or base-64 encoded strings 20 | */ 21 | function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); } 22 | function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); } 23 | function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); } 24 | function hex_hmac_md5(k, d) 25 | { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } 26 | function b64_hmac_md5(k, d) 27 | { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } 28 | function any_hmac_md5(k, d, e) 29 | { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); } 30 | 31 | /* 32 | * Perform a simple self-test to see if the VM is working 33 | */ 34 | function md5_vm_test() 35 | { 36 | return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72"; 37 | } 38 | 39 | /* 40 | * Calculate the MD5 of a raw string 41 | */ 42 | function rstr_md5(s) 43 | { 44 | return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); 45 | } 46 | 47 | /* 48 | * Calculate the HMAC-MD5, of a key and some data (raw strings) 49 | */ 50 | function rstr_hmac_md5(key, data) 51 | { 52 | var bkey = rstr2binl(key); 53 | if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8); 54 | 55 | var ipad = Array(16), opad = Array(16); 56 | for(var i = 0; i < 16; i++) 57 | { 58 | ipad[i] = bkey[i] ^ 0x36363636; 59 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 60 | } 61 | 62 | var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); 63 | return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); 64 | } 65 | 66 | /* 67 | * Convert a raw string to a hex string 68 | */ 69 | function rstr2hex(input) 70 | { 71 | try { hexcase } catch(e) { hexcase=0; } 72 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 73 | var output = ""; 74 | var x; 75 | for(var i = 0; i < input.length; i++) 76 | { 77 | x = input.charCodeAt(i); 78 | output += hex_tab.charAt((x >>> 4) & 0x0F) 79 | + hex_tab.charAt( x & 0x0F); 80 | } 81 | return output; 82 | } 83 | 84 | /* 85 | * Convert a raw string to a base-64 string 86 | */ 87 | function rstr2b64(input) 88 | { 89 | try { b64pad } catch(e) { b64pad=''; } 90 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 91 | var output = ""; 92 | var len = input.length; 93 | for(var i = 0; i < len; i += 3) 94 | { 95 | var triplet = (input.charCodeAt(i) << 16) 96 | | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) 97 | | (i + 2 < len ? input.charCodeAt(i+2) : 0); 98 | for(var j = 0; j < 4; j++) 99 | { 100 | if(i * 8 + j * 6 > input.length * 8) output += b64pad; 101 | else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); 102 | } 103 | } 104 | return output; 105 | } 106 | 107 | /* 108 | * Convert a raw string to an arbitrary string encoding 109 | */ 110 | function rstr2any(input, encoding) 111 | { 112 | var divisor = encoding.length; 113 | var i, j, q, x, quotient; 114 | 115 | /* Convert to an array of 16-bit big-endian values, forming the dividend */ 116 | var dividend = Array(Math.ceil(input.length / 2)); 117 | for(i = 0; i < dividend.length; i++) 118 | { 119 | dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); 120 | } 121 | 122 | /* 123 | * Repeatedly perform a long division. The binary array forms the dividend, 124 | * the length of the encoding is the divisor. Once computed, the quotient 125 | * forms the dividend for the next step. All remainders are stored for later 126 | * use. 127 | */ 128 | var full_length = Math.ceil(input.length * 8 / 129 | (Math.log(encoding.length) / Math.log(2))); 130 | var remainders = Array(full_length); 131 | for(j = 0; j < full_length; j++) 132 | { 133 | quotient = Array(); 134 | x = 0; 135 | for(i = 0; i < dividend.length; i++) 136 | { 137 | x = (x << 16) + dividend[i]; 138 | q = Math.floor(x / divisor); 139 | x -= q * divisor; 140 | if(quotient.length > 0 || q > 0) 141 | quotient[quotient.length] = q; 142 | } 143 | remainders[j] = x; 144 | dividend = quotient; 145 | } 146 | 147 | /* Convert the remainders to the output string */ 148 | var output = ""; 149 | for(i = remainders.length - 1; i >= 0; i--) 150 | output += encoding.charAt(remainders[i]); 151 | 152 | return output; 153 | } 154 | 155 | /* 156 | * Encode a string as utf-8. 157 | * For efficiency, this assumes the input is valid utf-16. 158 | */ 159 | function str2rstr_utf8(input) 160 | { 161 | var output = ""; 162 | var i = -1; 163 | var x, y; 164 | 165 | while(++i < input.length) 166 | { 167 | /* Decode utf-16 surrogate pairs */ 168 | x = input.charCodeAt(i); 169 | y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; 170 | if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) 171 | { 172 | x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); 173 | i++; 174 | } 175 | 176 | /* Encode output as utf-8 */ 177 | if(x <= 0x7F) 178 | output += String.fromCharCode(x); 179 | else if(x <= 0x7FF) 180 | output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), 181 | 0x80 | ( x & 0x3F)); 182 | else if(x <= 0xFFFF) 183 | output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), 184 | 0x80 | ((x >>> 6 ) & 0x3F), 185 | 0x80 | ( x & 0x3F)); 186 | else if(x <= 0x1FFFFF) 187 | output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), 188 | 0x80 | ((x >>> 12) & 0x3F), 189 | 0x80 | ((x >>> 6 ) & 0x3F), 190 | 0x80 | ( x & 0x3F)); 191 | } 192 | return output; 193 | } 194 | 195 | /* 196 | * Encode a string as utf-16 197 | */ 198 | function str2rstr_utf16le(input) 199 | { 200 | var output = ""; 201 | for(var i = 0; i < input.length; i++) 202 | output += String.fromCharCode( input.charCodeAt(i) & 0xFF, 203 | (input.charCodeAt(i) >>> 8) & 0xFF); 204 | return output; 205 | } 206 | 207 | function str2rstr_utf16be(input) 208 | { 209 | var output = ""; 210 | for(var i = 0; i < input.length; i++) 211 | output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, 212 | input.charCodeAt(i) & 0xFF); 213 | return output; 214 | } 215 | 216 | /* 217 | * Convert a raw string to an array of little-endian words 218 | * Characters >255 have their high-byte silently ignored. 219 | */ 220 | function rstr2binl(input) 221 | { 222 | var output = Array(input.length >> 2); 223 | for(var i = 0; i < output.length; i++) 224 | output[i] = 0; 225 | for(var i = 0; i < input.length * 8; i += 8) 226 | output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32); 227 | return output; 228 | } 229 | 230 | /* 231 | * Convert an array of little-endian words to a string 232 | */ 233 | function binl2rstr(input) 234 | { 235 | var output = ""; 236 | for(var i = 0; i < input.length * 32; i += 8) 237 | output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF); 238 | return output; 239 | } 240 | 241 | /* 242 | * Calculate the MD5 of an array of little-endian words, and a bit length. 243 | */ 244 | function binl_md5(x, len) 245 | { 246 | /* append padding */ 247 | x[len >> 5] |= 0x80 << ((len) % 32); 248 | x[(((len + 64) >>> 9) << 4) + 14] = len; 249 | 250 | var a = 1732584193; 251 | var b = -271733879; 252 | var c = -1732584194; 253 | var d = 271733878; 254 | 255 | for(var i = 0; i < x.length; i += 16) 256 | { 257 | var olda = a; 258 | var oldb = b; 259 | var oldc = c; 260 | var oldd = d; 261 | 262 | a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); 263 | d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); 264 | c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); 265 | b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); 266 | a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); 267 | d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); 268 | c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); 269 | b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); 270 | a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); 271 | d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); 272 | c = md5_ff(c, d, a, b, x[i+10], 17, -42063); 273 | b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); 274 | a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); 275 | d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); 276 | c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); 277 | b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); 278 | 279 | a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); 280 | d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); 281 | c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); 282 | b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); 283 | a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); 284 | d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); 285 | c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); 286 | b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); 287 | a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); 288 | d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); 289 | c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); 290 | b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); 291 | a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); 292 | d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); 293 | c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); 294 | b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); 295 | 296 | a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); 297 | d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); 298 | c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); 299 | b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); 300 | a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); 301 | d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); 302 | c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); 303 | b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); 304 | a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); 305 | d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); 306 | c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); 307 | b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); 308 | a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); 309 | d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); 310 | c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); 311 | b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); 312 | 313 | a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); 314 | d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); 315 | c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); 316 | b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); 317 | a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); 318 | d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); 319 | c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); 320 | b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); 321 | a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); 322 | d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); 323 | c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); 324 | b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); 325 | a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); 326 | d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); 327 | c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); 328 | b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); 329 | 330 | a = safe_add(a, olda); 331 | b = safe_add(b, oldb); 332 | c = safe_add(c, oldc); 333 | d = safe_add(d, oldd); 334 | } 335 | return Array(a, b, c, d); 336 | } 337 | 338 | /* 339 | * These functions implement the four basic operations the algorithm uses. 340 | */ 341 | function md5_cmn(q, a, b, x, s, t) 342 | { 343 | return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); 344 | } 345 | function md5_ff(a, b, c, d, x, s, t) 346 | { 347 | return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); 348 | } 349 | function md5_gg(a, b, c, d, x, s, t) 350 | { 351 | return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); 352 | } 353 | function md5_hh(a, b, c, d, x, s, t) 354 | { 355 | return md5_cmn(b ^ c ^ d, a, b, x, s, t); 356 | } 357 | function md5_ii(a, b, c, d, x, s, t) 358 | { 359 | return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); 360 | } 361 | 362 | /* 363 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 364 | * to work around bugs in some JS interpreters. 365 | */ 366 | function safe_add(x, y) 367 | { 368 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 369 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 370 | return (msw << 16) | (lsw & 0xFFFF); 371 | } 372 | 373 | /* 374 | * Bitwise rotate a 32-bit number to the left. 375 | */ 376 | function bit_rol(num, cnt) 377 | { 378 | return (num << cnt) | (num >>> (32 - cnt)); 379 | } 380 | -------------------------------------------------------------------------------- /js/github.commits.widget-min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * JSMin 3 | * Javascript Compressor 4 | * http://www.crockford.com/ 5 | * http://www.smallsharptools.com/Projects/Packer/ 6 | */ 7 | 8 | // github.commits.widget-min.js 9 | 10 | (function(globals){var 11 | authUsername,authToken,apiRoot="https://github.com/api/v2/json/",jsonp=function(url,callback,context){var id=+new Date,script=document.createElement("script");while(gh.__jsonp_callbacks[id]!==undefined) 12 | id+=Math.random();gh.__jsonp_callbacks[id]=function(){delete gh.__jsonp_callbacks[id];callback.apply(context,arguments);};var prefix="?";if(url.indexOf("?")>=0) 13 | prefix="&";url+=prefix+"callback="+encodeURIComponent("gh.__jsonp_callbacks["+id+"]");if(authUsername&&authToken){url+="&login="+authUsername+"&authToken="+authToken;} 14 | script.setAttribute("src",apiRoot+url);document.getElementsByTagName('head')[0].appendChild(script);},post=function(url,vals){var 15 | form=document.createElement("form"),iframe=document.createElement("iframe"),doc=iframe.contentDocument!==undefined?iframe.contentDocument:iframe.contentWindow.document,key,field;vals=vals||{};form.setAttribute("method","post");form.setAttribute("action",apiRoot+url);for(key in vals){if(vals.hasOwnProperty(key)){field=document.createElement("input");field.type="hidden";field.value=encodeURIComponent(vals[key]);form.appendChild(field);}} 16 | iframe.setAttribute("style","display: none;");doc.body.appendChild(form);document.body.appendChild(iframe);form.submit();},authRequired=function(username){if(!authUsername||!authToken||authUsername!==username){throw new TypeError("gh: Must be authenticated to do that.");}},paramify=function(params){var str="",key;for(key in params)if(params.hasOwnProperty(key)) 17 | str+=key+"="+params[key]+"&";return str.replace(/&$/,"");},withTempApiRoot=function(tempApiRoot,fn){return function(){var oldRoot=apiRoot;apiRoot=tempApiRoot;fn.apply(this,arguments);apiRoot=oldRoot;};},gh=globals.gh={};gh.__jsonp_callbacks={};gh.authenticate=function(username,token){authUsername=username;authToken=token;return this;};gh.user=function(username){if(!(this instanceof gh.user)){return new gh.user(username);} 18 | this.username=username;};gh.user.prototype.show=function(callback,context){jsonp("user/show/"+this.username,callback,context);return this;};gh.user.prototype.update=function(params){authRequired(this.username);var key,postData={login:authUsername,token:authToken};for(key in params){if(params.hasOwnProperty(key)){postData["values["+key+"]"]=encodeURIComponent(params[key]);}} 19 | post("user/show/"+this.username,postData);return this;};gh.user.prototype.following=function(callback,context){jsonp("user/show/"+this.username+"/following",callback,context);};gh.user.prototype.followers=function(callback,context){jsonp("user/show/"+this.username+"/followers",callback,context);};gh.user.prototype.follow=function(user){authRequired.call(this);post("user/follow/"+user);return this;};gh.user.prototype.unfollow=function(user){authRequired.call(this);post("user/unfollow/"+user);return this;};gh.user.prototype.watching=function(callback,context){jsonp("repos/watched/"+this.username,callback,context);return this;};gh.user.prototype.repos=function(callback,context){gh.repo.forUser(this.username,callback,context);return this;};gh.user.prototype.forkRepo=function(user,repo){authRequired(this.username);post("repos/fork/"+user+"/"+repo);return this;};gh.user.prototype.pushable=function(callback,context){authRequired(authUsername);jsonp("repos/pushable",callback,context);};gh.user.prototype.publicGists=withTempApiRoot("http://gist.github.com/api/v1/json/gists/",function(callback,context){jsonp(this.username,callback,context);return this;});gh.user.search=function(query,callback,context){jsonp("user/search/"+query,callback,context);return this;};gh.repo=function(user,repo){if(!(this instanceof gh.repo)){return new gh.repo(user,repo);} 20 | this.repo=repo;this.user=user;};gh.repo.prototype.show=function(callback,context){jsonp("repos/show/"+this.user+"/"+this.repo,callback,context);return this;};gh.repo.prototype.update=function(params){authRequired(this.user);var key,postData={login:authUsername,token:authToken};for(key in params){if(params.hasOwnProperty(key)){postData["values["+key+"]"]=encodeURIComponent(params[key]);}} 21 | post("repos/show/"+this.user+"/"+this.repo,postData);return this;};gh.repo.prototype.tags=function(callback,context){jsonp("repos/show/"+this.user+"/"+this.repo+"/tags",callback,context);return this;};gh.repo.prototype.branches=function(callback,context){jsonp("repos/show/"+this.user+"/"+this.repo+"/branches",callback,context);return this;};gh.repo.prototype.languages=function(callback,context){jsonp("/repos/show/"+this.user+"/"+this.repo+"/languages",callback,context);return this;};gh.repo.prototype.network=function(callback,context){jsonp("repos/show/"+this.user+"/"+this.repo+"/network",callback,context);return this;};gh.repo.prototype.contributors=function(callback,context,showAnon){var url="repos/show/"+this.user+"/"+this.repo+"/contributors";if(showAnon) 22 | url+="/anon";jsonp(url,callback,context);return this;};gh.repo.prototype.collaborators=function(callback,context){jsonp("repos/show/"+this.user+"/"+this.repo+"/collaborators",callback,context);return this;};gh.repo.prototype.addCollaborator=function(collaborator){authRequired(this.user);post("repos/collaborators/"+this.repo+"/add/"+collaborator);return this;};gh.repo.prototype.removeCollaborator=function(collaborator){authRequired(this.user);post("repos/collaborators/"+this.repo+"/remove/"+collaborator);return this;};gh.repo.prototype.setPrivate=function(){authRequired(this.user);post("repo/set/private/"+this.repo);return this;};gh.repo.prototype.setPublic=function(){authRequired(this.user);post("repo/set/public/"+this.repo);return this;};gh.repo.search=function(query,opts,callback,context){var url="repos/search/"+query.replace(" ","+");if(typeof opts==="function"){opts={};callback=arguments[1];context=arguments[2];} 23 | url+="?"+paramify(opts);return this;};gh.repo.forUser=function(user,callback,context){jsonp("repos/show/"+user,callback,context);return this;};gh.repo.create=function(name,opts){authRequired(authUsername);opts.name=name;post("repos/create",opts);return this;};gh.repo.del=function(name){authRequired(authUsername);post("repos/delete/"+name);return this;};gh.commit=function(user,repo,sha){if(!(this instanceof gh.commit)) 24 | return new gh.commit(user,repo,sha);this.user=user;this.repo=repo;this.sha=sha;};gh.commit.prototype.show=function(callback,context){jsonp("commits/show/"+this.user+"/"+this.repo+"/"+this.sha,callback,context);return this;};gh.commit.forBranch=function(user,repo,branch,callback,context){jsonp("commits/list/"+user+"/"+repo+"/"+branch,callback,context);return this;};gh.commit.forPath=function(user,repo,branch,path,callback,context){jsonp("commits/list/"+user+"/"+repo+"/"+branch+"/"+path,callback,context);return this;};gh.issue=function(user,repo,number){if(!(this instanceof gh.issue)) 25 | return new gh.commit(user,repo,number);this.user=user;this.repo=repo;this.number=number;};gh.issue.prototype.show=function(callback,context){jsonp("issues/show/"+this.user+"/"+this.repo+"/"+this.number,callback,context);return this;};gh.issue.prototype.comments=function(callback,context){jsonp("issues/comments/"+this.user+"/"+this.repo+"/"+this.number,callback,context);return this;};gh.issue.prototype.close=function(){authRequired(this.user);post("issues/close/"+this.user+"/"+this.repo+"/"+this.number);return this;};gh.issue.prototype.reopen=function(){authRequired(this.user);post("issues/reopen/"+this.user+"/"+this.repo+"/"+this.number);return this;};gh.issue.prototype.update=function(title,body){authRequired(this.user);post("issues/edit/"+this.user+"/"+this.repo+"/"+this.number,{title:title,body:body});return this;};gh.issue.prototype.addLabel=function(label){post("issues/label/add/"+this.user+"/"+this.repo+"/"+label+"/"+this.number);return this;};gh.issue.prototype.removeLabel=function(label){post("issues/label/remove/"+this.user+"/"+this.repo+"/"+label+"/"+this.number);return this;};gh.issue.prototype.comment=function(comment){authRequired(authUsername);post("/issues/comment/"+user+"/"+repo+"/"+this.number,{comment:comment});return this;};gh.issue.labels=function(user,repo){jsonp("issues/labels/"+user+"/"+repo,callback,context);return this;};gh.issue.open=function(repo,title,body){authRequired(authUsername);post("issues/open/"+authUsername+"/"+repo,{title:title,body:body});return this;};gh.issue.search=function(user,repo,state,query,callback,context){jsonp("/issues/search/"+user+"/"+repo+"/"+state+"/"+query,callback,context);return this;};gh.issue.list=function(user,repo,state,callback,context){jsonp("issues/list/"+user+"/"+repo+"/"+state,callback,context);return this;};gh.gist=function(id){if(!(this instanceof gh.gist)){return new gh.gist(id);} 26 | this.id=id;};gh.gist.prototype.show=withTempApiRoot("http://gist.github.com/api/v1/json/",function(callback,context){jsonp(this.id,callback,cont);return this;});gh.gist.prototype.file=withTempApiRoot("http://gist.github.com/raw/v1/json/",function(filename,callback,context){jsonp(this.id+"/"+filename,callback,cont);return this;});gh.object=function(user,repo){if(!(this instanceof gh.object)){return new gh.object(user,repo);} 27 | this.user=user;this.repo=repo;};gh.object.prototype.tree=function(sha,callback,context){jsonp("tree/show/"+this.user+"/"+this.repo+"/"+sha,callback,context);return this;};gh.object.prototype.blob=function(path,sha,callback,context){jsonp("blob/show/"+this.user+"/"+this.repo+"/"+sha+"/"+path,callback,context);return this;};gh.object.prototype.blobMeta=function(path,sha,callback,context){jsonp("blob/show/"+this.user+"/"+this.repo+"/"+sha+"/"+path+"?meta=1",callback,context);return this;};gh.object.prototype.blobAll=function(branch,callback,context){jsonp("blob/all/"+this.user+"/"+this.repo+"/"+branch,callback,context);return this;};gh.object.prototype.blobFull=function(sha,callback,context){jsonp("blob/full/"+this.user+"/"+this.repo+"/"+sha,callback,context);return this;};gh.network=function(user,repo){if(!(this instanceof gh.network)){return new gh.network(user,repo);} 28 | this.user=user;this.repo=repo;};gh.network.prototype.data=withTempApiRoot("http://github.com/",function(nethash,start,end,callback,context){jsonp(this.user+"/"+this.repo+"/network_data_chunk?" 29 | +nethash+"&"+start+"&"+end,callback,context);return this;});gh.network.prototype.meta=withTempApiRoot("http://github.com/",function(callback,context){jsonp(this.user+"/"+this.repo+"/network_meta",callback,context);return this;});}(window));var hexcase=0;var b64pad="";function hex_md5(s){return rstr2hex(rstr_md5(str2rstr_utf8(s)));} 30 | function b64_md5(s){return rstr2b64(rstr_md5(str2rstr_utf8(s)));} 31 | function any_md5(s,e){return rstr2any(rstr_md5(str2rstr_utf8(s)),e);} 32 | function hex_hmac_md5(k,d) 33 | {return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k),str2rstr_utf8(d)));} 34 | function b64_hmac_md5(k,d) 35 | {return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k),str2rstr_utf8(d)));} 36 | function any_hmac_md5(k,d,e) 37 | {return rstr2any(rstr_hmac_md5(str2rstr_utf8(k),str2rstr_utf8(d)),e);} 38 | function md5_vm_test() 39 | {return hex_md5("abc").toLowerCase()=="900150983cd24fb0d6963f7d28e17f72";} 40 | function rstr_md5(s) 41 | {return binl2rstr(binl_md5(rstr2binl(s),s.length*8));} 42 | function rstr_hmac_md5(key,data) 43 | {var bkey=rstr2binl(key);if(bkey.length>16)bkey=binl_md5(bkey,key.length*8);var ipad=Array(16),opad=Array(16);for(var i=0;i<16;i++) 44 | {ipad[i]=bkey[i]^0x36363636;opad[i]=bkey[i]^0x5C5C5C5C;} 45 | var hash=binl_md5(ipad.concat(rstr2binl(data)),512+data.length*8);return binl2rstr(binl_md5(opad.concat(hash),512+128));} 46 | function rstr2hex(input) 47 | {try{hexcase}catch(e){hexcase=0;} 48 | var hex_tab=hexcase?"0123456789ABCDEF":"0123456789abcdef";var output="";var x;for(var i=0;i>>4)&0x0F) 50 | +hex_tab.charAt(x&0x0F);} 51 | return output;} 52 | function rstr2b64(input) 53 | {try{b64pad}catch(e){b64pad='';} 54 | var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var output="";var len=input.length;for(var i=0;iinput.length*8)output+=b64pad;else output+=tab.charAt((triplet>>>6*(3-j))&0x3F);}} 57 | return output;} 58 | function rstr2any(input,encoding) 59 | {var divisor=encoding.length;var i,j,q,x,quotient;var dividend=Array(Math.ceil(input.length/2));for(i=0;i0||q>0) 64 | quotient[quotient.length]=q;} 65 | remainders[j]=x;dividend=quotient;} 66 | var output="";for(i=remainders.length-1;i>=0;i--) 67 | output+=encoding.charAt(remainders[i]);return output;} 68 | function str2rstr_utf8(input) 69 | {var output="";var i=-1;var x,y;while(++i>>6)&0x1F),0x80|(x&0x3F));else if(x<=0xFFFF) 75 | output+=String.fromCharCode(0xE0|((x>>>12)&0x0F),0x80|((x>>>6)&0x3F),0x80|(x&0x3F));else if(x<=0x1FFFFF) 76 | output+=String.fromCharCode(0xF0|((x>>>18)&0x07),0x80|((x>>>12)&0x3F),0x80|((x>>>6)&0x3F),0x80|(x&0x3F));} 77 | return output;} 78 | function str2rstr_utf16le(input) 79 | {var output="";for(var i=0;i>>8)&0xFF);return output;} 81 | function str2rstr_utf16be(input) 82 | {var output="";for(var i=0;i>>8)&0xFF,input.charCodeAt(i)&0xFF);return output;} 84 | function rstr2binl(input) 85 | {var output=Array(input.length>>2);for(var i=0;i>5]|=(input.charCodeAt(i/8)&0xFF)<<(i%32);return output;} 88 | function binl2rstr(input) 89 | {var output="";for(var i=0;i>5]>>>(i%32))&0xFF);return output;} 91 | function binl_md5(x,len) 92 | {x[len>>5]|=0x80<<((len)%32);x[(((len+64)>>>9)<<4)+14]=len;var a=1732584193;var b=-271733879;var c=-1732584194;var d=271733878;for(var i=0;i>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&0xFFFF);} 107 | function bit_rol(num,cnt) 108 | {return(num<>>(32-cnt));} 109 | (function($){function widget(element,options){this.element=element;this.options=options;} 110 | widget.prototype=(function(){function _widgetRun(widget){if(!widget.options){widget.element.append('Options for widget are not set.');return;} 111 | var element=widget.element;var user=widget.options.user;var repo=widget.options.repo;var branch=widget.options.branch;var last=widget.options.last==undefined?0:widget.options.last;var limitMessage=widget.options.limitMessageTo==undefined?0:widget.options.limitMessageTo;element.append('

    Widget intitalization, please wait...

    ');gh.commit.forBranch(user,repo,branch,function(data){var commits=data.commits;var totalCommits=(last');for(var c=0;c'+' '+avatar(commits[c].author.email)+' '+author(commits[c].author.login)+' commited '+message(commits[c].message,commits[c].url)+' '+when(commits[c].committed_date)+'');} 112 | element.append('
');element.append('
by github.commits.widget
');function avatar(email){var emailHash=hex_md5(email);return'';} 113 | function author(login){return''+login+'';} 114 | function message(commitMessage,url){if(limitMessage>0&&commitMessage.length>limitMessage) 115 | {commitMessage=commitMessage.substr(0,limitMessage)+'...';} 116 | return'"'+''+commitMessage+'"';} 117 | function when(commitDate){var commitTime=new Date(commitDate).getTime();var todayTime=new Date().getTime();var differenceInDays=Math.floor(((todayTime-commitTime)/(24*3600*1000)));if(differenceInDays==0){var differenceInHours=Math.floor(((todayTime-commitTime)/(3600*1000)));if(differenceInHours==0){var differenceInMinutes=Math.floor(((todayTime-commitTime)/(600*1000)));if(differenceInMinutes==0){return'just now';} 118 | return'about '+differenceInMinutes+' minutes ago';} 119 | return'about '+differenceInHours+' hours ago';} 120 | return differenceInDays+' days ago';}});} 121 | return{run:function(){_widgetRun(this);}};})();$.fn.githubInfoWidget=function(options){var w=new widget(this,options);w.run();return this;}})(jQuery); 122 | -------------------------------------------------------------------------------- /js/github.js: -------------------------------------------------------------------------------- 1 | // ## Client-side Javascript API wrapper for GitHub 2 | // 3 | // Tries to map one-to-one with the GitHub API V2, but in a Javascripty manner. 4 | 5 | (function (globals) { 6 | 7 | // Before we implement the API methods, we will define all of our private 8 | // variables and helper functions with one `var` statement. 9 | var 10 | 11 | // The username and authentication token of the library's user. 12 | authUsername, 13 | authToken, 14 | 15 | // To save keystrokes when we make JSONP calls to the HTTP API, we will keep 16 | // track of the root from which all V2 urls extend. 17 | apiRoot = "https://github.com/api/v2/json/", 18 | 19 | // Send a JSONP request to the Github API that calls `callback` with 20 | // the `context` argument as `this`. 21 | // 22 | // The `url` parameter is concatenated with the apiRoot, for the reasons 23 | // mentioned above. The way that we are supporting non-global, anonymous 24 | // functions is by sticking them in the globally exposed 25 | // `gh.__jsonp_callbacks` object with a "unique" `id` that is the current 26 | // time in milliseconds. Once the callback is called, it is deleted from the 27 | // object to prevent memory leaks. 28 | jsonp = function (url, callback, context) { 29 | var id = +new Date, 30 | script = document.createElement("script"); 31 | 32 | while (gh.__jsonp_callbacks[id] !== undefined) 33 | id += Math.random(); // Avoid slight possibility of id clashes. 34 | 35 | gh.__jsonp_callbacks[id] = function () { 36 | delete gh.__jsonp_callbacks[id]; 37 | callback.apply(context, arguments); 38 | }; 39 | 40 | var prefix = "?"; 41 | if (url.indexOf("?") >= 0) 42 | prefix = "&"; 43 | 44 | url += prefix + "callback=" + encodeURIComponent("gh.__jsonp_callbacks[" + id + "]"); 45 | if (authUsername && authToken) { 46 | url += "&login=" + authUsername + "&authToken=" + authToken; 47 | } 48 | script.setAttribute("src", apiRoot + url); 49 | 50 | document.getElementsByTagName('head')[0].appendChild(script); 51 | }, 52 | 53 | // Send an HTTP POST. Unfortunately, it isn't possible to support a callback 54 | // with the resulting data. (Please prove me wrong if you can!) 55 | // 56 | // This is implemented with a hack to get around the cross-domain 57 | // restrictions on ajax calls. Basically, a form is created that will POST 58 | // to the GitHub API URL, stuck inside an iframe so that it won't redirect 59 | // this page, and then submitted. 60 | post = function (url, vals) { 61 | var 62 | form = document.createElement("form"), 63 | iframe = document.createElement("iframe"), 64 | doc = iframe.contentDocument !== undefined ? 65 | iframe.contentDocument : 66 | iframe.contentWindow.document, 67 | key, field; 68 | vals = vals || {}; 69 | 70 | form.setAttribute("method", "post"); 71 | form.setAttribute("action", apiRoot + url); 72 | for (key in vals) { 73 | if (vals.hasOwnProperty(key)) { 74 | field = document.createElement("input"); 75 | field.type = "hidden"; 76 | field.value = encodeURIComponent(vals[key]); 77 | form.appendChild(field); 78 | } 79 | } 80 | 81 | iframe.setAttribute("style", "display: none;"); 82 | doc.body.appendChild(form); 83 | document.body.appendChild(iframe); 84 | form.submit(); 85 | }, 86 | 87 | // This helper function will throw a TypeError if the library user is not 88 | // properly authenticated. Otherwise, it silently returns. 89 | authRequired = function (username) { 90 | if (!authUsername || !authToken || authUsername !== username) { 91 | throw new TypeError("gh: Must be authenticated to do that."); 92 | } 93 | }, 94 | 95 | // Convert an object to a url parameter string. 96 | // 97 | // paramify({foo:1, bar:3}) -> "foo=1&bar=3". 98 | paramify = function (params) { 99 | var str = "", key; 100 | for (key in params) if (params.hasOwnProperty(key)) 101 | str += key + "=" + params[key] + "&"; 102 | return str.replace(/&$/, ""); 103 | }, 104 | 105 | // Get around how the GH team haven't migrated all the API to version 2, and 106 | // how gists use a different api root. 107 | withTempApiRoot = function (tempApiRoot, fn) { 108 | return function () { 109 | var oldRoot = apiRoot; 110 | apiRoot = tempApiRoot; 111 | fn.apply(this, arguments); 112 | apiRoot = oldRoot; 113 | }; 114 | }, 115 | 116 | // Expose the global `gh` variable, through which every API method is 117 | // accessed, but keep a local variable around so we can reference it easily. 118 | gh = globals.gh = {}; 119 | 120 | // Psuedo private home for JSONP callbacks (which are required to be global 121 | // by the nature of JSONP, as discussed earlier). 122 | gh.__jsonp_callbacks = {}; 123 | 124 | // Authenticate as a user. Does not try to validate at any point; that job 125 | // is up to each individual method, which calls `authRequired` as needed. 126 | gh.authenticate = function (username, token) { 127 | authUsername = username; 128 | authToken = token; 129 | return this; 130 | }; 131 | 132 | // ### Users 133 | 134 | // The constructor for user objects. Just creating an instance of a user 135 | // doesn't fetch any data from GitHub, you need to get explicit about what 136 | // you want to do that. 137 | // 138 | // var huddlej = gh.user("huddlej"); 139 | gh.user = function (username) { 140 | if ( !(this instanceof gh.user)) { 141 | return new gh.user(username); 142 | } 143 | this.username = username; 144 | }; 145 | 146 | // Show basic user info; you can get more info if you are authenticated as 147 | // this user. 148 | // 149 | // gh.user("fitzgen").show(function (data) { 150 | // console.log(data.user); 151 | // }); 152 | gh.user.prototype.show = function (callback, context) { 153 | jsonp("user/show/" + this.username, callback, context); 154 | return this; 155 | }; 156 | 157 | // Update a user's info. You must be authenticated as this user for this to 158 | // succeed. 159 | // 160 | // TODO: example 161 | gh.user.prototype.update = function (params) { 162 | authRequired(this.username); 163 | var key, postData = { 164 | login: authUsername, 165 | token: authToken 166 | }; 167 | for (key in params) { 168 | if (params.hasOwnProperty(key)) { 169 | postData["values["+key+"]"] = encodeURIComponent(params[key]); 170 | } 171 | } 172 | post("user/show/" + this.username, postData); 173 | return this; 174 | }; 175 | 176 | // Get a list of who this user is following. 177 | // 178 | // TODO: example 179 | gh.user.prototype.following = function (callback, context) { 180 | jsonp("user/show/" + this.username + "/following", callback, context); 181 | }; 182 | 183 | // Find out what other users are following this user. 184 | // 185 | // TODO: example 186 | gh.user.prototype.followers = function (callback, context) { 187 | jsonp("user/show/" + this.username + "/followers", callback, context); 188 | }; 189 | 190 | // Make this user follow some other user. You must be authenticated as this 191 | // user for this to succeed. 192 | // 193 | // TODO: example 194 | gh.user.prototype.follow = function (user) { 195 | authRequired.call(this); 196 | post("user/follow/" + user); 197 | return this; 198 | }; 199 | 200 | // Make this user quit following the given `user`. You must be authenticated 201 | // as this user to succeed. 202 | // 203 | // TODO: example 204 | gh.user.prototype.unfollow = function (user) { 205 | authRequired.call(this); 206 | post("user/unfollow/" + user); 207 | return this; 208 | }; 209 | 210 | // Get a list of repositories that this user is watching. 211 | // 212 | // TODO: example 213 | gh.user.prototype.watching = function (callback, context) { 214 | jsonp("repos/watched/" + this.username, callback, context); 215 | return this; 216 | }; 217 | 218 | // Get a list of this user's repositories. 219 | // 220 | // gh.user("fitzgen").repos(function (data) { 221 | // alert(data.repositories.length); 222 | // }); 223 | gh.user.prototype.repos = function (callback, context) { 224 | gh.repo.forUser(this.username, callback, context); 225 | return this; 226 | }; 227 | 228 | // Make this user fork the repo that lives at 229 | // http://github.com/user/repo. You must be authenticated as this user for 230 | // this to succeed. 231 | // 232 | // gh.user("fitzgen").forkRepo("brianleroux", "wtfjs"); 233 | gh.user.prototype.forkRepo = function (user, repo) { 234 | authRequired(this.username); 235 | post("repos/fork/" + user + "/" + repo); 236 | return this; 237 | }; 238 | 239 | // Get a list of all repos that this user can push to (including ones that 240 | // they are just a collaborator on, and do not own). Must be authenticated 241 | // as this user. 242 | gh.user.prototype.pushable = function (callback, context) { 243 | authRequired(authUsername); 244 | jsonp("repos/pushable", callback, context); 245 | }; 246 | 247 | gh.user.prototype.publicGists = withTempApiRoot( 248 | "http://gist.github.com/api/v1/json/gists/", 249 | function (callback, context) { 250 | jsonp(this.username, callback, context); 251 | return this; 252 | } 253 | ); 254 | 255 | // Search users for `query`. 256 | gh.user.search = function (query, callback, context) { 257 | jsonp("user/search/" + query, callback, context); 258 | return this; 259 | }; 260 | 261 | // ### Repositories 262 | 263 | // This is the base constructor for creating repo objects. Note that this 264 | // won't actually hit the GitHub API until you specify what data you want, 265 | // or what action you wish to take via a prototype method. 266 | gh.repo = function (user, repo) { 267 | if ( !(this instanceof gh.repo)) { 268 | return new gh.repo(user, repo); 269 | } 270 | this.repo = repo; 271 | this.user = user; 272 | }; 273 | 274 | // Get basic information on this repo. 275 | // 276 | // gh.repo("schacon", "grit").show(function (data) { 277 | // console.log(data.repository.description); 278 | // }); 279 | gh.repo.prototype.show = function (callback, context) { 280 | jsonp("repos/show/" + this.user + "/" + this.repo, callback, context); 281 | return this; 282 | }; 283 | 284 | // Update the information for this repo. Must be authenticated as the 285 | // repository owner. Params can include: 286 | // 287 | // * description 288 | // * homepage 289 | // * has_wiki 290 | // * has_issues 291 | // * has_downloads 292 | gh.repo.prototype.update = function (params) { 293 | authRequired(this.user); 294 | var key, postData = { 295 | login: authUsername, 296 | token: authToken 297 | }; 298 | for (key in params) { 299 | if (params.hasOwnProperty(key)) { 300 | postData["values["+key+"]"] = encodeURIComponent(params[key]); 301 | } 302 | } 303 | post("repos/show/" + this.user + "/" + this.repo, postData); 304 | return this; 305 | }; 306 | 307 | // Get all tags for this repo. 308 | gh.repo.prototype.tags = function (callback, context) { 309 | jsonp("repos/show/" + this.user + "/" + this.repo + "/tags", 310 | callback, 311 | context); 312 | return this; 313 | }; 314 | 315 | // Get all branches in this repo. 316 | gh.repo.prototype.branches = function (callback, context) { 317 | jsonp("repos/show/" + this.user + "/" + this.repo + "/branches", 318 | callback, 319 | context); 320 | return this; 321 | }; 322 | 323 | // Gather line count information on the language(s) used in this repo. 324 | gh.repo.prototype.languages = function (callback, context) { 325 | jsonp("/repos/show/" + this.user + "/" + this.repo + "/languages", 326 | callback, 327 | context); 328 | return this; 329 | }; 330 | 331 | // Gather data on all the forks of this repo. 332 | gh.repo.prototype.network = function (callback, context) { 333 | jsonp("repos/show/" + this.user + "/" + this.repo + "/network", 334 | callback, 335 | context); 336 | return this; 337 | }; 338 | 339 | // All users who have contributed to this repo. Pass `true` to showAnon if you 340 | // want to see the non-github contributors. 341 | gh.repo.prototype.contributors = function (callback, context, showAnon) { 342 | var url = "repos/show/" + this.user + "/" + this.repo + "/contributors"; 343 | if (showAnon) 344 | url += "/anon"; 345 | jsonp(url, 346 | callback, 347 | context); 348 | return this; 349 | }; 350 | 351 | // Get all of the collaborators for this repo. 352 | gh.repo.prototype.collaborators = function (callback, context) { 353 | jsonp("repos/show/" + this.user + "/" + this.repo + "/collaborators", 354 | callback, 355 | context); 356 | return this; 357 | }; 358 | 359 | // Add a collaborator to this project. Must be authenticated. 360 | gh.repo.prototype.addCollaborator = function (collaborator) { 361 | authRequired(this.user); 362 | post("repos/collaborators/" + this.repo + "/add/" + collaborator); 363 | return this; 364 | }; 365 | 366 | // Remove a collaborator from this project. Must be authenticated. 367 | gh.repo.prototype.removeCollaborator = function (collaborator) { 368 | authRequired(this.user); 369 | post("repos/collaborators/" + this.repo + "/remove/" + collaborator); 370 | return this; 371 | }; 372 | 373 | // Make this repository private. Authentication required. 374 | gh.repo.prototype.setPrivate = function () { 375 | authRequired(this.user); 376 | post("repo/set/private/" + this.repo); 377 | return this; 378 | }; 379 | 380 | // Make this repository public. Authentication required. 381 | gh.repo.prototype.setPublic = function () { 382 | authRequired(this.user); 383 | post("repo/set/public/" + this.repo); 384 | return this; 385 | }; 386 | 387 | // Search for repositories. `opts` may include `start_page` or `language`, 388 | // which must be capitalized. 389 | gh.repo.search = function (query, opts, callback, context) { 390 | var url = "repos/search/" + query.replace(" ", "+"); 391 | if (typeof opts === "function") { 392 | opts = {}; 393 | callback = arguments[1]; 394 | context = arguments[2]; 395 | } 396 | url += "?" + paramify(opts); 397 | return this; 398 | }; 399 | 400 | // Get all the repos that are owned by `user`. 401 | gh.repo.forUser = function (user, callback, context) { 402 | jsonp("repos/show/" + user, callback, context); 403 | return this; 404 | }; 405 | 406 | // Create a repository. Must be authenticated. 407 | gh.repo.create = function (name, opts) { 408 | authRequired(authUsername); 409 | opts.name = name; 410 | post("repos/create", opts); 411 | return this; 412 | }; 413 | 414 | // Delete a repository. Must be authenticated. 415 | gh.repo.del = function (name) { 416 | authRequired(authUsername); 417 | post("repos/delete/" + name); 418 | return this; 419 | }; 420 | 421 | // ### Commits 422 | 423 | gh.commit = function (user, repo, sha) { 424 | if ( !(this instanceof gh.commit) ) 425 | return new gh.commit(user, repo, sha); 426 | this.user = user; 427 | this.repo = repo; 428 | this.sha = sha; 429 | }; 430 | 431 | gh.commit.prototype.show = function (callback, context) { 432 | jsonp("commits/show/" + this.user + "/" + this.repo + "/" + this.sha, 433 | callback, 434 | context); 435 | return this; 436 | }; 437 | 438 | // Get a list of all commits on a repos branch. 439 | gh.commit.forBranch = function (user, repo, branch, callback, context) { 440 | jsonp("commits/list/" + user + "/" + repo + "/" + branch, 441 | callback, 442 | context); 443 | return this; 444 | }; 445 | 446 | // Get a list of all commits on this path (file or dir). 447 | gh.commit.forPath = function (user, repo, branch, path, callback, context) { 448 | jsonp("commits/list/" + user + "/" + repo + "/" + branch + "/" + path, 449 | callback, 450 | context); 451 | return this; 452 | }; 453 | 454 | // ### Issues 455 | 456 | gh.issue = function (user, repo, number) { 457 | if ( !(this instanceof gh.issue) ) 458 | return new gh.commit(user, repo, number); 459 | this.user = user; 460 | this.repo = repo; 461 | this.number = number; 462 | }; 463 | 464 | // View this issue's info. 465 | gh.issue.prototype.show = function (callback, context) { 466 | jsonp("issues/show/" + this.user + "/" + this.repo + "/" + this.number, 467 | callback, 468 | context); 469 | return this; 470 | }; 471 | 472 | // Get a list of all comments on this issue. 473 | gh.issue.prototype.comments = function (callback, context) { 474 | jsonp("issues/comments/" + this.user + "/" + this.repo + "/" + this.number, 475 | callback, 476 | context); 477 | return this; 478 | }; 479 | 480 | // Close this issue. 481 | gh.issue.prototype.close = function () { 482 | authRequired(this.user); 483 | post("issues/close/" + this.user + "/" + this.repo + "/" + this.number); 484 | return this; 485 | }; 486 | 487 | // Reopen this issue. 488 | gh.issue.prototype.reopen = function () { 489 | authRequired(this.user); 490 | post("issues/reopen/" + this.user + "/" + this.repo + "/" + this.number); 491 | return this; 492 | }; 493 | 494 | // Reopen this issue. 495 | gh.issue.prototype.update = function (title, body) { 496 | authRequired(this.user); 497 | post("issues/edit/" + this.user + "/" + this.repo + "/" + this.number, { 498 | title: title, 499 | body: body 500 | }); 501 | return this; 502 | }; 503 | 504 | // Add `label` to this issue. If the label is not yet in the system, it will 505 | // be created. 506 | gh.issue.prototype.addLabel = function (label) { 507 | post("issues/label/add/" + this.user + "/" + this.repo + "/" + label + "/" + this.number); 508 | return this; 509 | }; 510 | 511 | // Remove a label from this issue. 512 | gh.issue.prototype.removeLabel = function (label) { 513 | post("issues/label/remove/" + this.user + "/" + this.repo + "/" + label + "/" + this.number); 514 | return this; 515 | }; 516 | 517 | // Comment on this issue as the user that is authenticated. 518 | gh.issue.prototype.comment = function (comment) { 519 | authRequired(authUsername); 520 | post("/issues/comment/" + user + "/" + repo + "/" + this.number, { 521 | comment: comment 522 | }); 523 | return this; 524 | }; 525 | 526 | // Get all issues' labels for the repo. 527 | gh.issue.labels = function (user, repo) { 528 | jsonp("issues/labels/" + user + "/" + repo, 529 | callback, 530 | context); 531 | return this; 532 | }; 533 | 534 | // Open an issue. Must be authenticated. 535 | gh.issue.open = function (repo, title, body) { 536 | authRequired(authUsername); 537 | post("issues/open/" + authUsername + "/" + repo, { 538 | title: title, 539 | body: body 540 | }); 541 | return this; 542 | }; 543 | 544 | // Search a repository's issue tracker. `state` can be "open" or "closed". 545 | gh.issue.search = function (user, repo, state, query, callback, context) { 546 | jsonp("/issues/search/" + user + "/" + repo + "/" + state + "/" + query, 547 | callback, 548 | context); 549 | return this; 550 | }; 551 | 552 | // Get a list of issues for the given repo. `state` can be "open" or 553 | // "closed". 554 | gh.issue.list = function (user, repo, state, callback, context) { 555 | jsonp("issues/list/" + user + "/" + repo + "/" + state, 556 | callback, 557 | context); 558 | return this; 559 | }; 560 | 561 | // ### Gists 562 | 563 | gh.gist = function (id) { 564 | if ( !(this instanceof gh.gist) ) { 565 | return new gh.gist(id); 566 | } 567 | this.id = id; 568 | }; 569 | 570 | gh.gist.prototype.show = withTempApiRoot( 571 | "http://gist.github.com/api/v1/json/", 572 | function (callback, context) { 573 | jsonp(this.id, callback, cont); 574 | return this; 575 | } 576 | ); 577 | 578 | gh.gist.prototype.file = withTempApiRoot( 579 | "http://gist.github.com/raw/v1/json/", 580 | function (filename, callback, context) { 581 | jsonp(this.id + "/" + filename, callback, cont); 582 | return this; 583 | } 584 | ); 585 | 586 | // ### Objects 587 | 588 | gh.object = function (user, repo) { 589 | if (!(this instanceof gh.object)) { 590 | return new gh.object(user, repo); 591 | } 592 | this.user = user; 593 | this.repo = repo; 594 | }; 595 | 596 | // Get the contents of a tree by tree SHA 597 | gh.object.prototype.tree = function (sha, callback, context) { 598 | jsonp("tree/show/" + this.user + "/" + this.repo + "/" + sha, 599 | callback, 600 | context); 601 | return this; 602 | }; 603 | 604 | // Get the data about a blob by tree SHA and path 605 | gh.object.prototype.blob = function (path, sha, callback, context) { 606 | jsonp("blob/show/" + this.user + "/" + this.repo + "/" + sha + "/" + path, 607 | callback, 608 | context); 609 | return this; 610 | }; 611 | 612 | // Get only blob meta 613 | gh.object.prototype.blobMeta = function (path, sha, callback, context) { 614 | jsonp("blob/show/" + this.user + "/" + this.repo + "/" + sha + "/" + path + "?meta=1", 615 | callback, 616 | context); 617 | return this; 618 | }; 619 | 620 | // Get list of blobs 621 | gh.object.prototype.blobAll = function (branch, callback, context) { 622 | jsonp("blob/all/" + this.user + "/" + this.repo + "/" + branch, 623 | callback, 624 | context); 625 | return this; 626 | }; 627 | 628 | // Get meta of each blob in tree 629 | gh.object.prototype.blobFull = function (sha, callback, context) { 630 | jsonp("blob/full/" + this.user + "/" + this.repo + "/" + sha, 631 | callback, 632 | context); 633 | return this; 634 | }; 635 | 636 | // ### Network 637 | 638 | gh.network = function(user, repo) { 639 | if (!(this instanceof gh.network)) { 640 | return new gh.network(user, repo); 641 | } 642 | this.user = user; 643 | this.repo = repo; 644 | }; 645 | 646 | gh.network.prototype.data = withTempApiRoot( 647 | "http://github.com/", 648 | function (nethash, start, end, callback, context) { 649 | jsonp(this.user + "/" + this.repo + "/network_data_chunk?" 650 | + nethash + "&" + start + "&" + end, 651 | callback, 652 | context); 653 | return this; 654 | } 655 | ); 656 | 657 | gh.network.prototype.meta = withTempApiRoot( 658 | "http://github.com/", 659 | function (callback, context) { 660 | jsonp(this.user + "/" + this.repo + "/network_meta", 661 | callback, 662 | context); 663 | return this; 664 | } 665 | ); 666 | 667 | }(window)); --------------------------------------------------------------------------------