├── .gitignore ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── dist ├── github.min.css └── github.min.js ├── package.json └── src ├── github.css └── github.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | test 4 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | dist: 'dist', 3 | bower: 'bower_components', 4 | src: 'src', 5 | banner: '/*!\n' + 6 | ' * <%= project.name %> - v<%= project.version %>\n'+ 7 | ' * Copyright (c) 2015-<%= grunt.template.today("yyyy") %> <%= project.author %>\n'+ 8 | ' */\n' 9 | }; 10 | 11 | var project = require('./package.json'); 12 | 13 | module.exports = function(grunt) { 14 | grunt.initConfig({ 15 | config: config, 16 | project: project, 17 | cssmin: { 18 | add_banner: { 19 | options: { 20 | banner: config.banner 21 | }, 22 | files: { 23 | '<%= config.dist %>/github.min.css': [ 24 | '<%= config.src %>/github.css' 25 | ] 26 | } 27 | } 28 | }, 29 | uglify: { 30 | options: { 31 | banner: config.banner 32 | }, 33 | dist: { 34 | files: { 35 | '<%= config.dist %>/github.min.js': [ 36 | '<%= config.src %>/github.js' 37 | ] 38 | } 39 | } 40 | }, 41 | clean: { 42 | build: { 43 | src: ["dist/*"] 44 | } 45 | } 46 | }); 47 | 48 | grunt.loadNpmTasks('grunt-contrib-clean'); 49 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 50 | grunt.loadNpmTasks('grunt-contrib-uglify'); 51 | 52 | grunt.registerTask( "wipe", [ "clean" ]) 53 | grunt.registerTask( "build", ["cssmin", "uglify:dist" ] ); 54 | 55 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 AKSHAY SHARMA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Github.js 2 | 3 | Github.js is a JavaScript plugin over [GitHub APIs v3](https://developer.github.com/v3/). It gives an easy way to feature your GitHub open-source contributions on your website or portfolio. 4 | 5 | # Demo 6 | 7 | [Click here](http://akshaykumar6.github.io/github-js) for live examples. 8 | 9 | #Dependency 10 | 11 | The plugin has hard dependency on [underscore.js](http://underscorejs.org/)(~v1.6.0). You can download it from [here](https://github.com/jashkenas/underscore/archive/1.6.0.zip). 12 | 13 | # Installation 14 | 15 | Add **github.js** and **github.css** to your project. [Download v0.1.3](https://github.com/akshaykumar6/github-js/archive/v0.1.3.zip). 16 | 17 | ```html 18 | 19 | 20 | // Add underscore.js 21 | 22 | 23 | ``` 24 | 25 | Github.js is available via [bower](http://bower.io/search/?q=githubjs) and [npm](https://www.npmjs.com/package/githubjs). 26 | ``` 27 | $ bower install --save githubjs 28 | $ npm install --save githubjs 29 | ``` 30 | 31 | # Usage 32 | ### User Profile 33 | 34 | ```javascript 35 | Github.userProfile({ 36 | username: "jashkenas", 37 | selector: ".user-1" 38 | }); 39 | ``` 40 | 41 | ### User Activity 42 | 43 | ```javascript 44 | Github.userActivity({ 45 | username: "torvalds", 46 | selector: ".user-2" 47 | }); 48 | ``` 49 | 50 | ### Repository Profile 51 | 52 | ```javascript 53 | Github.repoProfile({ 54 | username: 'atom', 55 | reponame: 'atom', 56 | selector: '.repo-1' 57 | }); 58 | ``` 59 | 60 | ### Repository Activity 61 | 62 | ```javascript 63 | Github.repoActivity({ 64 | username: 'joyent', 65 | reponame: 'node', 66 | selector: '.repo-2' 67 | }); 68 | ``` 69 | 70 | ### Organization Profile 71 | 72 | ```javascript 73 | Github.orgProfile({ 74 | orgname: 'facebook', 75 | selector: '.org-1' 76 | }); 77 | ``` 78 | 79 | ### Organization Activity 80 | 81 | ```javascript 82 | Github.orgActivity({ 83 | orgname: 'google', 84 | selector: '.org-2' 85 | }); 86 | ``` 87 | 88 | # Documentation 89 | * [Complete Documentation](https://github.com/akshaykumar6/github-js/wiki) 90 | * [Annotated Source Code](http://akshaykumar6.github.io/github-js/docs/github.html) 91 | 92 | # Contribute 93 | To start contributing to Github.js, clone the repository and start playing. 94 | ``` 95 | $ git clone git@github.com:akshaykumar6/github-js.git 96 | $ cd github-js 97 | ``` 98 | 99 | If you're not familiar with Git, visit the [Git homepage](http://git-scm.com/) to download Git for your platform. 100 | 101 | **Got a bug or a feature request?** [Please open a new issue](https://github.com/akshaykumar6/github-js/issues). 102 | 103 | # License 104 | **github-js** © 2015, Akshay Sharma Released under the [MIT License](http://mit-license.org/). 105 | 106 | Authored and maintained by [Akshay Sharma](http://akshaykumar6.github.io/). 107 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-js", 3 | "main": "github-js", 4 | "version": "0.1.3", 5 | "homepage": "http://akshaykumar6.github.io/github-js", 6 | "authors": [ 7 | "Akshay Sharma " 8 | ], 9 | "description": "Javascript Plugin over Github APIs.", 10 | "keywords": [ 11 | "github","Javascript","API","github-js","github.js" 12 | ], 13 | "license": "MIT", 14 | "private": false, 15 | "ignore": [ 16 | "src", 17 | ".gitignore" 18 | ], 19 | "dependencies": { 20 | "underscore": "~1.6.0" 21 | }, 22 | "devDependencies": {} 23 | } 24 | -------------------------------------------------------------------------------- /dist/github.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * githubjs - v0.1.3 3 | * Copyright (c) 2015-2015 Akshay Sharma 4 | */ 5 | 6 | .gt-container a{color:#3572B0;text-decoration:none}.gt-container a:active,.gt-container a:focus,.gt-container a:hover{text-decoration:underline}.gt-container *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.gt-container{position:relative;width:100%;border-radius:3px;border:1px solid #D8D8D8;background:#FAFAFA;font-size:1rem;min-width:270px}.gt-header{position:relative;width:100%;padding-top:10px;background-color:#F5F5F5;z-index:2}.gt-org-avatar,.gt-usr-avatar{width:100px;height:100px;margin:0 auto}.gt-org-avatar a,.gt-usr-avatar a{width:100px;height:100px;display:block}.gt-org-avatar img,.gt-usr-avatar img{width:100%;height:100%;border-radius:50%}.gt-org-name,.gt-usr-name{padding:10px 20px;text-align:center}.gt-header .user-name{display:block;overflow:hidden;width:100%;font-size:1.6rem;line-height:30px;text-overflow:ellipsis}.gt-header .user-login{display:block;overflow:hidden;width:100%;font-size:1.25rem;font-style:normal;font-weight:300;line-height:24px;color:#666;text-overflow:ellipsis}.gt-header .user-login:hover{text-decoration:underline}.gt-usr-details{height:50px}.gt-repo-details{height:60px}.gt-usr-folng,.gt-usr-folwr,.gt-usr-repo{float:left;width:33.33%;text-align:center;padding-top:5px;height:50px}.gt-usr-dt,.gt-usr-txt{display:block}.gt-repo-details a,.gt-usr-details a{text-decoration:none!important;color:#000}.gt-usr-folng:hover,.gt-usr-folwr:hover,.gt-usr-repo:hover{background-color:#E3E3E3}.gt-usr-name p{margin:5px 0}.gt-shadow{border-bottom:1px solid #DDD;box-shadow:0 2px 2px -1px rgba(0,0,0,.4);-webkit-box-shadow:0 2px 2px -1px rgba(0,0,0,.4);-moz-box-shadow:0 2px 2px -1px rgba(0,0,0,.4)}.gt-org-link{display:inline-block;margin:5px}.gt-org-repos{display:block;clear:both}.gt-activity-cnt{background-color:#FFF;position:relative;width:100%;height:300px;overflow-y:auto}.gt-time-str{color:#666;font-size:.9rem}.gt-activity{padding:10px 5px;border-top:1px solid #D8D8D8;word-break:break-all}.gt-no-activity{padding:10px 5px;text-align:center}.gt-activity .gt-avatar-cnt{float:left;width:5%;min-width:35px;padding-left:5px;padding-bottom:5px}.gt-activity .gt-usr-avatar{width:30px;height:30px}.gt-act-cnt{display:inline-block;display:-moz-inline-stack;float:left;width:91%;padding-left:7px}.gt-clearfix{clear:both}.gt-act-cnt p{margin:2px 0;color:#666;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;width:100%;display:block;white-space:nowrap}.gt-act-cnt .pull-req-info{display:inline-block;padding:3px 7px;margin-top:5px;color:rgba(0,0,0,.5);background:#e8f1f6;border-radius:3px;width:auto}.gt-commit-list{margin:0;padding:0;list-style-type:none;font-size:.9rem!important}.gt-commit-item{margin:5px 0}.gt-commit-msg{color:#666;margin:0 5px}.gt-compare-link{font-size:.9rem}.gt-scrollbar{-webkit-overflow-scrolling:touch}.gt-scrollbar::-webkit-scrollbar{height:9px;width:9px}.gt-scrollbar::-webkit-scrollbar-button:end:increment,.gt-scrollbar::-webkit-scrollbar-button:start:decrement{background:0 0;display:none}.gt-scrollbar::-webkit-scrollbar-track-piece{background:#F2F2F2;border:1px solid #E3E3E3}.gt-scrollbar::-webkit-scrollbar-thumb:horizontal:hover,.gt-scrollbar::-webkit-scrollbar-thumb:vertical:hover{background:#888;opacity:.6}.gt-scrollbar::-webkit-scrollbar-thumb:horizontal,.gt-scrollbar::-webkit-scrollbar-thumb:vertical{background:#BBB;display:block;height:50px;opacity:.2}.gt-org-img,.gt-usr-img{background-repeat:no-repeat;background-position:60%;border-radius:50%;width:100px;height:100px;background-size:112%}.gt-repo-lg-stat{width:100%;height:10px;clear:both;background-color:#38AFB9}.gt-repo-lg-cnt{position:relative;float:left;height:100%}.gt-repo-lg-name{height:100%;position:relative}.gt-repo-lg-name[data-title]:hover:after{content:attr(data-title);font-size:12px;padding:2px 8px;color:#fff;position:absolute;left:40%;top:175%;white-space:nowrap;z-index:200;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;background-color:#222}.gt-repo-lg-name:hover:before{border-bottom-color:#222;border-width:5px;left:48%}.gt-repo-lg-name:before{border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none;top:75%;z-index:201}.gt-loading-txt{text-align:center;padding:5px 0;color:#999} -------------------------------------------------------------------------------- /dist/github.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * githubjs - v0.1.3 3 | * Copyright (c) 2015-2015 Akshay Sharma 4 | */ 5 | !function(a,b){"function"==typeof define&&define.amd?define(["underscore"],b):"object"==typeof exports?module.exports=b(require("underscore")):a.Github=b(a._)}(this,function(a){var b={};b.version="0.1.3";var c="https://api.github.com/";b.userProfile=function(a){if(a=e.initialize(a,["username","selector"],0)){var b=c+"users/"+a.username;e.getData(b,a,e.getUserProfileHTML)}else console.error("Parameters not passed correctly")},b.repoProfile=function(a){if(a=e.initialize(a,["username","selector","reponame"],0)){var b=c+"repos/"+a.username+"/"+a.reponame;e.getData(b,a,e.getRepoProfileHTML)}else console.error("Parameters not passed correctly")},b.orgProfile=function(a){if(a=e.initialize(a,["orgname","selector"],0)){var b=c+"orgs/"+a.orgname;e.getData(b,a,e.getOrgProfileHTML)}else console.error("Parameters not passed correctly")},b.userActivity=function(a){if(a=e.initialize(a,["username","selector"],1)){var b=c+"users/"+a.username,d=b+"/events";e.getData(b,a,e.getUserProfileHTML),e.getData(d,a,e.getPublicActivityHTML)}else console.error("Parameters not passed correctly")},b.repoActivity=function(a){if(a=e.initialize(a,["username","selector","reponame"],1)){var b=c+"repos/"+a.username+"/"+a.reponame,d=b+"/events";e.getData(b,a,e.getRepoProfileHTML),e.getData(d,a,e.getPublicActivityHTML)}else console.error("Parameters not passed correctly")},b.orgActivity=function(a){if(a=e.initialize(a,["orgname","selector"],1)){var b=c+"orgs/"+a.orgname,d=b+"/events";e.getData(b,a,e.getOrgProfileHTML),e.getData(d,a,e.getPublicActivityHTML)}else console.error("Parameters not passed correctly")};var d={parentTpl:'
Loading..
<%if(type){%>
Loading..
<%}%>
',userProfileTpl:'
<%= name%>
',repoProfileTpl:'
<%= name%>

<%= description%>

',orgProfileTpl:'
<%= name%><%if(blog){%><%}%><%if(email){%><%}%>
<%= public_repos%> Public Repositories
',gitActivityTpl:'
<%= timeString%>
<%= userLink%><%= message%>
',CommitCommentEvent:" commented on commit <%= commentLink%>

<%= payload.comment.body%>

",CreateEvent:" created <%= payload.ref_type%> <%= branchLink%> at <%= repoLink%> ",DeleteEvent:" deleted <%= payload.ref%> <%= payload.ref_type%> at <%= repoLink%> ",ForkEvent:" forked <%= repoLink%> to <%= forkLink%> ",GollumEvent:" <%= actionType%> the <%= repoLink%> wiki

<%= wikiMessage%>

",IssueCommentEvent:" commented on issue <%= commentLink%>

<%= payload.comment.body%>

",IssuesEvent:" <%= payload.action%> issue <%= issueUrl%> ",MemberEvent:" added <%= memberLink%> to <%= repoLink%> ",PublicEvent:" open sourced <%= repoLink%> ",PullRequestEvent:' <%= payload.action%> pull request <%= mergeRequestUrl%>

<%= payload.pull_request.title%>

<%= payload.pull_request.commits%><%if(payload.pull_request.commits > 1){%> commits <%}else{%> commit <%}%> with <%= payload.pull_request.changed_files%> <%if(payload.pull_request.commits > 1){%> files <%}else{%> file <%}%> changed.

',PullRequestReviewCommentEvent:" commented on pull request <%= pullCommentUrl%>

<%= payload.comment.body%>

",PushEvent:" pushed to <%= branchLink%> at <%= repoLink%> <%= commitsHtml%>",ReleaseEvent:" released <%= tagLink%> at <%= repoLink%>
<%= zipLink%>",WatchEvent:" starred <%= repoLink%> ",noActivityTpl:'
There are no public events for this account in past 90 days.
',notFoundTpl:'
This account does not exist.
'},e={initialize:function(a,b,c){for(var f=0;fg;g++){var h=a[g],i=h.payload;switch(h.timeString=e.millisecondsToStr(new Date-new Date(h.created_at)),h.userLink=e.getGitHubLink(h.actor.login,h.actor.login),h.repoLink=e.getGitHubLink(h.repo.name,h.repo.name),h.branchLink="",i.ref&&(h.branch="refs/heads/"===i.ref.substring(0,11)?i.ref.substring(11):i.ref,h.branchLink=e.getGitHubLink(h.repo.name+"/tree/"+h.branch,h.branch)),h.type){case"CommitCommentEvent":h.commentLink=e.getLink(i.comment.html_url,h.repo.name+"@"+i.comment.commit_id.substring(0,6));break;case"CreateEvent":break;case"DeleteEvent":break;case"ForkEvent":h.forkLink=e.getGitHubLink(i.forkee.html_url,i.forkee.full_name);break;case"GollumEvent":var j=i.pages[0];h.actionType=j.action,h.wikiMessage=h.actionType.charAt(0).toUpperCase()+h.actionType.slice(1)+" ",h.wikiMessage+=e.getLink(j.html_url,j.title);break;case"IssueCommentEvent":h.commentLink=e.getLink(i.comment.html_url,h.repo.name+"#"+i.issue.number);break;case"IssuesEvent":h.issueUrl=e.getLink(i.issue.html_url,h.repo.name+"#"+i.issue.number);break;case"MemberEvent":h.memberLink=e.getGitHubLink(i.member.login,i.member.login);break;case"PublicEvent":break;case"PullRequestEvent":h.mergeRequestUrl=e.getLink(i.pull_request.html_url,h.repo.name+"#"+i.pull_request.number);break;case"PullRequestReviewCommentEvent":h.pullCommentUrl=e.getLink(i.comment.html_url,h.repo.name+"#"+i.pull_request.number);break;case"PushEvent":h.commitsHtml=e.getCommitsHTML(h);break;case"ReleaseEvent":h.tagLink=e.getLink(i.release.html_url,i.release.tag_name),h.zipLink=e.getLink(i.release.zipball_url,"Download Source Code (zip)");break;case"WatchEvent":}h.message=e.getRenderedHTML(d[h.type],h),c+=e.getRenderedHTML(d.gitActivityTpl,h)}e.renderContent(c,b.selector,".gt-activity-cnt")},getCommitsHTML:function(a){var b,c,d,f,g,h='
    ',i="",j=a.payload,k=j.commits.length,l=j.before+"..."+j.head;for(g=0;k>g&&!(g>1);g++)f=j.commits[g],b='
  • ',c=e.getGitHubLink(a.repo.name+"/commit/"+f.sha,f.sha.substring(0,6)),d=''+f.message.substring(0,150)+"",b+=c,b+=d,b+="
  • ",h+=b;return 2===k?i=e.getGitHubLink(a.repo.name+"/compare/"+l,"View comparison for these 2 commits »","gt-compare-link"):k>2&&(i=e.getGitHubLink(a.repo.name+"/compare/"+l,k-2+" more "+e.getPluralWord(k-2,"commit")+" »","gt-compare-link")),h+="
",h+=i},getData:function(a,b,c){var f,g;g=new XMLHttpRequest,g.open("GET",a,!0),b.OAuth&&g.setRequestHeader("Authorization","Token "+b.OAuth),g.onload=function(){g.status>=200&&g.status<400?(f=JSON.parse(g.responseText),c(f,b)):(e.renderContent(e.getRenderedHTML(d.notFoundTpl,f),b.selector,".gt-container"),console.error("An error occurred while connecting to GitHub API."))},g.onerror=function(){console.error("An error occurred while connecting to GitHub API.")},g.send()},getLink:function(a,b,c){return b||(b=a),"undefined"==typeof c&&(c=""),e.getRenderedHTML('<%=title%>',{url:a,title:b})},getGitHubLink:function(a,b,c){return b||(b=a),"undefined"==typeof c&&(c=""),e.getLink("https://github.com/"+a,b,c)},getPluralWord:function(a,b){return 1!==a?b+"s":b},getLanguageHTML:function(b,c){var d,f=[],g=0,h="";a.each(b,function(a,b){var c={};c.language=b,c.size=a,f.push(c),g+=a}),f=f.sort(function(a,b){return b.size-a.size}),a.each(f,function(a){d=(parseInt(a.size)/g*100).toFixed(1),h+='
'}),e.renderContent(h,c.selector,".gt-repo-lg-stat")},getRandomColor:function(){return Math.random().toString(16).substring(2,8)},millisecondsToStr:function(a){function b(a){return a>1?"s ago":" ago"}var c=Math.floor(a/1e3),d=Math.floor(c/31536e3);if(d)return d+" year"+b(d);var e=Math.floor((c%=31536e3)/2592e3);if(e)return e+" month"+b(e);var f=Math.floor((c%=2592e3)/86400);if(f)return f+" day"+b(f);var g=Math.floor((c%=86400)/3600);if(g)return"about "+g+" hour"+b(g);var h=Math.floor((c%=3600)/60);if(h)return h+" minute"+b(h);var i=c%60;return i?i+" second"+b(i):"just now"},renderContent:function(a,b,c){for(var d=document.querySelectorAll(b),e=0;e30?30:b:30}};return b}); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "githubjs", 3 | "version": "0.1.3", 4 | "description": "Javascript Plugin over Github APIs.", 5 | "main": "Gruntfile.js", 6 | "start_year": "2015", 7 | "devDependencies": { 8 | "grunt": "~0.4.5", 9 | "grunt-contrib-copy": "~0.6.0", 10 | "grunt-contrib-uglify": "~0.6.0", 11 | "grunt-contrib-cssmin": "~0.10.0", 12 | "grunt-contrib-clean": "~0.6.0" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/akshaykumar6/github-js" 17 | }, 18 | "keywords": [ 19 | "github-js", 20 | "github.js", 21 | "github", 22 | "Javascript", 23 | "API" 24 | ], 25 | "author": "Akshay Sharma ", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/akshaykumar6/github-js/issues" 29 | }, 30 | "homepage": "http://akshaykumar6.github.io/github-js", 31 | "directories": { 32 | "test": "test" 33 | }, 34 | "dependencies": { 35 | "grunt": "^0.4.5", 36 | "grunt-contrib-clean": "^0.6.0", 37 | "grunt-contrib-uglify": "^0.6.0", 38 | "grunt-contrib-cssmin": "^0.10.0", 39 | "grunt-contrib-copy": "^0.6.0" 40 | }, 41 | "scripts": { 42 | "test": "echo \"Error: no test specified\" && exit 1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/github.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Generic CSS 3 | */ 4 | 5 | .gt-container a { 6 | color: #3572B0; 7 | text-decoration: none; 8 | } 9 | .gt-container a:focus, .gt-container a:hover, .gt-container a:active { 10 | text-decoration: underline; 11 | } 12 | .gt-container *{ 13 | -webkit-box-sizing: border-box; 14 | -moz-box-sizing: border-box; 15 | box-sizing: border-box; 16 | } 17 | .gt-container{ 18 | position: relative; 19 | width: 100%; 20 | background-color: #FFF; 21 | border-radius: 3px; 22 | border: 1px solid #D8D8D8; 23 | background: #FAFAFA; 24 | font-size: 1rem; 25 | min-width: 270px; 26 | } 27 | .gt-header{ 28 | position: relative; 29 | width: 100%; 30 | padding-top: 10px; 31 | background-color: #F5F5F5; 32 | z-index: 2; 33 | } 34 | .gt-usr-avatar, .gt-org-avatar{ 35 | width: 100px; 36 | height: 100px; 37 | margin: 0 auto; 38 | } 39 | .gt-usr-avatar a, .gt-org-avatar a{ 40 | width: 100px; 41 | height: 100px; 42 | display: block; 43 | } 44 | .gt-usr-avatar img, .gt-org-avatar img{ 45 | width: 100%; 46 | height: 100%; 47 | border-radius: 50%; 48 | } 49 | .gt-usr-name, .gt-org-name{ 50 | padding: 10px 20px; 51 | text-align: center; 52 | } 53 | .gt-header .user-name{ 54 | display: block; 55 | overflow: hidden; 56 | width: 100%; 57 | font-size: 1.6rem; 58 | line-height: 30px; 59 | text-overflow: ellipsis; 60 | } 61 | .gt-header .user-login{ 62 | display: block; 63 | overflow: hidden; 64 | width: 100%; 65 | font-size: 1.25rem; 66 | font-style: normal; 67 | font-weight: 300; 68 | line-height: 24px; 69 | color: #666; 70 | text-overflow: ellipsis; 71 | } 72 | .gt-header .user-login:hover{ 73 | text-decoration: underline; 74 | } 75 | .gt-usr-details{ 76 | height: 50px; 77 | } 78 | .gt-repo-details{ 79 | height: 60px; 80 | } 81 | .gt-usr-repo,.gt-usr-folwr,.gt-usr-folng{ 82 | float: left; 83 | width: 33.33%; 84 | text-align: center; 85 | padding-top: 5px; 86 | height: 50px; 87 | } 88 | .gt-usr-txt{ 89 | display: block; 90 | } 91 | .gt-usr-dt{ 92 | display: block; 93 | } 94 | .gt-usr-details a,.gt-repo-details a{ 95 | text-decoration: none !important; 96 | color: #000; 97 | } 98 | .gt-usr-repo:hover,.gt-usr-folwr:hover,.gt-usr-folng:hover{ 99 | background-color: #E3E3E3; 100 | } 101 | .gt-usr-name p{ 102 | margin: 5px 0; 103 | } 104 | .gt-shadow{ 105 | border-bottom: 1px solid #DDD; 106 | box-shadow: 0 2px 2px -1px rgba(0,0,0,.4); 107 | -webkit-box-shadow: 0 2px 2px -1px rgba(0,0,0,.4); 108 | -moz-box-shadow: 0 2px 2px -1px rgba(0,0,0,.4); 109 | } 110 | 111 | /** 112 | * Organization 113 | */ 114 | 115 | .gt-org-link{ 116 | display: inline-block; 117 | margin: 5px; 118 | } 119 | .gt-org-repos{ 120 | display: block; 121 | clear: both; 122 | } 123 | /** 124 | * Activity 125 | */ 126 | .gt-activity-cnt{ 127 | background-color: #FFF; 128 | position: relative; 129 | width: 100%; 130 | height: 300px; 131 | overflow-y: auto; 132 | } 133 | .gt-time-cnt{ 134 | 135 | } 136 | .gt-time-str{ 137 | color: #666; 138 | font-size: 0.9rem; 139 | } 140 | .gt-activity{ 141 | padding: 10px 5px; 142 | border-top: 1px solid #D8D8D8; 143 | word-break: break-all; 144 | } 145 | .gt-no-activity{ 146 | padding: 10px 5px; 147 | text-align: center; 148 | } 149 | .gt-activity .gt-avatar-cnt{ 150 | float: left; 151 | width: 5%; 152 | min-width: 35px; 153 | padding-left: 5px; 154 | padding-bottom: 5px; 155 | } 156 | .gt-activity .gt-usr-avatar{ 157 | width: 30px; 158 | height: 30px; 159 | } 160 | .gt-act-cnt{ 161 | display: inline-block; 162 | display: -moz-inline-stack; 163 | float: left; 164 | width: 91%; 165 | padding-left: 7px; 166 | } 167 | .gt-clearfix{ 168 | clear: both; 169 | } 170 | .gt-act-cnt p{ 171 | margin: 2px 0px; 172 | color: #666; 173 | font-size: 0.9rem; 174 | overflow: hidden; 175 | text-overflow: ellipsis; 176 | width: 100%; 177 | display: block; 178 | white-space: nowrap; 179 | } 180 | .gt-act-cnt .pull-req-info{ 181 | display: inline-block; 182 | padding: 3px 7px; 183 | margin-top: 5px; 184 | color: rgba(0,0,0,0.5); 185 | background: #e8f1f6; 186 | border-radius: 3px; 187 | width: auto; 188 | } 189 | .gt-commit-list{ 190 | margin: 0; 191 | padding: 0; 192 | list-style-type: none; 193 | font-size: 0.9rem !important; 194 | } 195 | .gt-commit-item{ 196 | margin: 5px 0; 197 | } 198 | .gt-commit-msg{ 199 | color: #666; 200 | margin: 0 5px; 201 | } 202 | .gt-compare-link{ 203 | font-size: 0.9rem; 204 | } 205 | .gt-scrollbar { 206 | -webkit-overflow-scrolling: touch 207 | } 208 | .gt-scrollbar::-webkit-scrollbar { 209 | height: 9px; 210 | width: 9px 211 | } 212 | .gt-scrollbar::-webkit-scrollbar-button:start:decrement, .gt-scrollbar::-webkit-scrollbar-button:end:increment { 213 | background: transparent; 214 | display: none 215 | } 216 | .gt-scrollbar::-webkit-scrollbar-track-piece { 217 | background: #F2F2F2; 218 | border: 1px solid #E3E3E3; 219 | } 220 | .gt-scrollbar::-webkit-scrollbar-thumb:vertical:hover, .gt-scrollbar::-webkit-scrollbar-thumb:horizontal:hover { 221 | background: #888; 222 | opacity: 0.6; 223 | } 224 | .gt-scrollbar::-webkit-scrollbar-thumb:vertical, .gt-scrollbar::-webkit-scrollbar-thumb:horizontal { 225 | background: #BBB; 226 | display: block; 227 | height: 50px; 228 | opacity: 0.2; 229 | } 230 | .gt-org-img, .gt-usr-img{ 231 | background-repeat: no-repeat; 232 | background-position: 60%; 233 | border-radius: 50%; 234 | width: 100px; 235 | height: 100px; 236 | background-size: 112%; 237 | } 238 | .gt-repo-lg-stat{ 239 | width: 100%; 240 | height: 10px; 241 | clear: both; 242 | background-color: #38AFB9; 243 | } 244 | .gt-repo-lg-cnt{ 245 | position: relative; 246 | float: left; 247 | height: 100%; 248 | } 249 | .gt-repo-lg-name{ 250 | height: 100%; 251 | position: relative; 252 | } 253 | .gt-repo-lg-name[data-title]:hover:after{ 254 | content: attr(data-title); 255 | font-size: 12px; 256 | padding: 2px 8px; 257 | color: white; 258 | position: absolute; 259 | left: 40%; 260 | top: 175%; 261 | white-space: nowrap; 262 | z-index: 200; 263 | -moz-border-radius: 5px; 264 | -webkit-border-radius: 5px; 265 | border-radius: 5px; 266 | background-color: #222; 267 | } 268 | 269 | .gt-repo-lg-name:hover:before { 270 | border-bottom-color: #222; 271 | border-width: 5px; 272 | left: 48%; 273 | } 274 | .gt-repo-lg-name:before { 275 | border: solid transparent; 276 | content: " "; 277 | height: 0; 278 | width: 0; 279 | position: absolute; 280 | pointer-events: none; 281 | top: 75%; 282 | z-index: 201; 283 | } 284 | .gt-loading-txt{ 285 | text-align: center; 286 | padding: 5px 0; 287 | color: #999; 288 | } 289 | -------------------------------------------------------------------------------- /src/github.js: -------------------------------------------------------------------------------- 1 | // Github.js - v0.1.3 2 | 3 | // © 2015, Akshay Sharma Released under the MIT License. 4 | 5 | (function (root, factory) { 6 | 7 | // Set up library appropriately for the environment 8 | if (typeof define === 'function' && define.amd) { 9 | // Define for AMD 10 | define(['underscore'], factory); 11 | } else if (typeof exports === 'object') { 12 | // Export for Node, CommonJS-like modules 13 | module.exports = factory(require('underscore')); 14 | } else { 15 | // As browser global (root is window here) 16 | root.Github = factory(root._); 17 | } 18 | 19 | }(this, function (_) { 20 | 21 | var Github = {}; 22 | 23 | // Current version of the library. Keep in sync with `package.json` 24 | Github.version = '0.1.3'; 25 | 26 | // Common GitHub API URL 27 | var gitApiUrl = 'https://api.github.com/'; 28 | 29 | // userProfile - render's the github user details to selector 30 | // @param Type - JSON -> options [username, selector] 31 | 32 | Github.userProfile = function (options) { 33 | 34 | if(options = gitMethods.initialize(options, ['username','selector'], 0)){ 35 | var userUrl = gitApiUrl + 'users/' + options.username; 36 | gitMethods.getData(userUrl, options, gitMethods.getUserProfileHTML); 37 | } else{ 38 | console.error("Parameters not passed correctly"); 39 | } 40 | 41 | }; 42 | 43 | // 44 | // repoProfile - render's the github repo details to selector 45 | // @param Type - JSON -> options [username, reponame, selector] 46 | // 47 | Github.repoProfile = function (options) { 48 | 49 | if(options = gitMethods.initialize(options, ['username','selector','reponame'], 0)){ 50 | var repoUrl = gitApiUrl + 'repos/' + options.username +'/'+ options.reponame; 51 | gitMethods.getData(repoUrl, options, gitMethods.getRepoProfileHTML); 52 | } else{ 53 | console.error("Parameters not passed correctly"); 54 | } 55 | 56 | }; 57 | 58 | // 59 | // orgProfile - render's the github organization details to selector 60 | // @param Type - JSON -> options [orgname, selector] 61 | // 62 | Github.orgProfile = function (options) { 63 | 64 | if(options = gitMethods.initialize(options, ['orgname','selector'], 0)){ 65 | var orgUrl = gitApiUrl + 'orgs/' + options.orgname; 66 | gitMethods.getData(orgUrl, options, gitMethods.getOrgProfileHTML); 67 | } else{ 68 | console.error("Parameters not passed correctly"); 69 | } 70 | 71 | }; 72 | 73 | // 74 | // userActivity - render's the github user activity to selector 75 | // @param Type - JSON -> options [username, selector and limit (optional)] 76 | // 77 | Github.userActivity = function (options) { 78 | 79 | if(options = gitMethods.initialize(options, ['username','selector'], 1)){ 80 | var userUrl = gitApiUrl + 'users/' + options.username, 81 | eventsUrl = userUrl + '/events'; 82 | gitMethods.getData(userUrl, options, gitMethods.getUserProfileHTML); 83 | gitMethods.getData(eventsUrl, options, gitMethods.getPublicActivityHTML); 84 | } else{ 85 | console.error("Parameters not passed correctly"); 86 | } 87 | 88 | }; 89 | 90 | // 91 | // repoActivity - render's the github repository activity to selector 92 | // @param Type - JSON -> options [username, reponame, selector and limit (optional)] 93 | // 94 | Github.repoActivity = function (options) { 95 | 96 | if(options = gitMethods.initialize(options, ['username','selector','reponame'], 1)){ 97 | var repoUrl = gitApiUrl + 'repos/' + options.username +'/'+ options.reponame, 98 | eventsUrl = repoUrl + '/events'; 99 | gitMethods.getData(repoUrl, options, gitMethods.getRepoProfileHTML); 100 | gitMethods.getData(eventsUrl, options, gitMethods.getPublicActivityHTML); 101 | } else{ 102 | console.error("Parameters not passed correctly"); 103 | } 104 | 105 | }; 106 | 107 | // 108 | // orgActivity - render's the github organization activity to selector 109 | // @param Type - JSON -> options [orgname, selector and limit (optional)] 110 | // 111 | Github.orgActivity = function (options) { 112 | 113 | if(options = gitMethods.initialize(options, ['orgname','selector'], 1)){ 114 | var orgUrl = gitApiUrl + 'orgs/' + options.orgname, 115 | eventsUrl = orgUrl + '/events'; 116 | gitMethods.getData(orgUrl, options, gitMethods.getOrgProfileHTML); 117 | gitMethods.getData(eventsUrl, options, gitMethods.getPublicActivityHTML); 118 | } else{ 119 | console.error("Parameters not passed correctly"); 120 | } 121 | 122 | }; 123 | 124 | // Underscore templates for profiles, activities, etc. 125 | var gitTemplates = { 126 | // Parent container template 127 | parentTpl: '
'+ 128 | '
'+ 129 | '
Loading..
'+ 130 | '
'+ 131 | '<%if(type){%>
'+ 132 | '
Loading..
'+ 133 | '
<%}%>'+ 134 | '
', 135 | // User profile template 136 | userProfileTpl: '
'+ 137 | ''+ 138 | '
'+ 139 | '
'+ 140 | '
'+ 141 | '
'+ 142 | '<%= name%>'+ 143 | ''+ 144 | ''+ 145 | ''+ 146 | '
'+ 147 | '', 167 | // Repository profile template 168 | repoProfileTpl: '
'+ 169 | '<%= name%>'+ 170 | ''+ 171 | ''+ 172 | ''+ 173 | '

'+ 174 | '<%= description%>'+ 175 | '

'+ 176 | '
'+ 177 | '
'+ 178 | ''+ 184 | ''+ 190 | ''+ 196 | '
'+ 197 | '
'+ 198 | '
', 199 | // Organization profile template 200 | orgProfileTpl: '
'+ 201 | ''+ 202 | '
'+ 203 | '
'+ 204 | '
'+ 205 | '
'+ 206 | '<%= name%>'+ 207 | '<%if(blog){%>'+ 208 | ''+ 209 | '<%}%>'+ 210 | '<%if(email){%>'+ 211 | ''+ 212 | '<%}%>'+ 213 | '
<%= public_repos%>'+ 214 | ' Public Repositories'+ 215 | '
', 216 | // Parent activity container template 217 | gitActivityTpl: '
'+ 218 | '
'+ 219 | ''+ 220 | ''+ 221 | ''+ 222 | '
'+ 223 | '
'+ 224 | '
<%= timeString%>
'+ 225 | '<%= userLink%>'+'<%= message%>'+ 226 | '
'+ 227 | '
'+ 228 | '
', 229 | // Activity templates keyed with activity type 230 | CommitCommentEvent:' commented on commit <%= commentLink%> '+ 231 | '

<%= payload.comment.body%>

', 232 | CreateEvent: ' created <%= payload.ref_type%> <%= branchLink%> at <%= repoLink%> ', 233 | DeleteEvent: ' deleted <%= payload.ref%> <%= payload.ref_type%> at <%= repoLink%> ', 234 | ForkEvent: ' forked <%= repoLink%> to <%= forkLink%> ', 235 | GollumEvent: ' <%= actionType%> the <%= repoLink%> wiki'+ 236 | '

<%= wikiMessage%>

', 237 | IssueCommentEvent: ' commented on issue <%= commentLink%> '+ 238 | '

<%= payload.comment.body%>

', 239 | IssuesEvent: ' <%= payload.action%> issue <%= issueUrl%> ', 240 | MemberEvent: ' added <%= memberLink%> to <%= repoLink%> ', 241 | PublicEvent: ' open sourced <%= repoLink%> ', 242 | PullRequestEvent: ' <%= payload.action%> pull request <%= mergeRequestUrl%> '+ 243 | '

<%= payload.pull_request.title%>

'+ 244 | '

<%= payload.pull_request.commits%><%if(payload.pull_request.commits > 1){%> commits <%}else{%> commit <%}%> '+ 245 | 'with <%= payload.pull_request.changed_files%> <%if(payload.pull_request.commits > 1){%> files <%}else{%> file <%}%> changed.

', 246 | PullRequestReviewCommentEvent: ' commented on pull request <%= pullCommentUrl%> '+ 247 | '

<%= payload.comment.body%>

', 248 | PushEvent: ' pushed to <%= branchLink%> at <%= repoLink%> '+ 249 | '<%= commitsHtml%>', 250 | ReleaseEvent: ' released <%= tagLink%> at <%= repoLink%> '+ 251 | '
<%= zipLink%>', 252 | WatchEvent: ' starred <%= repoLink%> ', 253 | noActivityTpl: '
'+ 254 | ' There are no public events for this account in past 90 days. '+ 255 | '
', 256 | notFoundTpl: '
'+ 257 | ' This account does not exist. '+ 258 | '
' 259 | }; 260 | 261 | // Object for locally used methods 262 | var gitMethods = { 263 | // Check variables and render base template 264 | initialize: function(options, variables, type){ 265 | // Validate varaibles 266 | for (var i = 0; i < variables.length; i++) { 267 | if(!options[variables[i]]) 268 | return false; 269 | } 270 | // Type - 0 - only profile 271 | 272 | // Type - 1 - profile and acitivity feed 273 | gitMethods.renderContent(gitMethods.getRenderedHTML(gitTemplates['parentTpl'],{ 274 | type: type 275 | }),options.selector); 276 | 277 | // Set limit value 278 | options.limit = gitMethods.setLimit(options.limit); 279 | return options; 280 | }, 281 | 282 | // Check if value is integer 283 | checkInteger: function (value) { 284 | if (value === parseInt(value, 10)) 285 | return true; 286 | else 287 | return false; 288 | }, 289 | 290 | // Get the rendered template with data 291 | getRenderedHTML: function (template, data) { 292 | if (data) { 293 | return _.template(template)(data); 294 | } else{ 295 | return _.template(template)(); 296 | } 297 | }, 298 | 299 | // Render User profile HTML 300 | getUserProfileHTML: function (data, options){ 301 | gitMethods.renderContent(gitMethods.getRenderedHTML(gitTemplates.userProfileTpl, data), options.selector,'.gt-header'); 302 | }, 303 | 304 | // Render the repository profile HTML with language stats 305 | getRepoProfileHTML: function (data, options){ 306 | var languageUrl = gitApiUrl + 'repos/' + options.username +'/'+ options.reponame + '/languages'; 307 | // Render template 308 | gitMethods.renderContent(gitMethods.getRenderedHTML(gitTemplates.repoProfileTpl, data), options.selector,'.gt-header'); 309 | // Fetch language stat for repo 310 | gitMethods.getData(languageUrl, options, gitMethods.getLanguageHTML); 311 | }, 312 | 313 | // Render organization profile HTML 314 | getOrgProfileHTML: function (data, options){ 315 | gitMethods.renderContent(gitMethods.getRenderedHTML(gitTemplates.orgProfileTpl, data), options.selector,'.gt-header'); 316 | }, 317 | 318 | // Render recent public activities of user/repo/organization 319 | getPublicActivityHTML: function (data,options) { 320 | var html = ''; 321 | // Get min of limit of data size 322 | var length = (options.limit < data.length)? options.limit : data.length; 323 | 324 | if (length==0) { 325 | // If no activity in last 90 days 326 | html += gitMethods.getRenderedHTML(gitTemplates['noActivityTpl']); 327 | } 328 | else{ 329 | // Loop over all the activities 330 | for(var index = 0; index < length; index++){ 331 | var activity = data[index]; 332 | var payload = activity.payload; 333 | 334 | // Get attributes common to all activities 335 | activity.timeString = gitMethods.millisecondsToStr(new Date() - new Date(activity.created_at)); 336 | activity.userLink = gitMethods.getGitHubLink(activity.actor.login, activity.actor.login); 337 | activity.repoLink = gitMethods.getGitHubLink(activity.repo.name, activity.repo.name); 338 | 339 | // Get the branch name 340 | activity.branchLink = ''; 341 | if (payload.ref) { 342 | if (payload.ref.substring(0, 11) === 'refs/heads/') { 343 | activity.branch = payload.ref.substring(11); 344 | } else { 345 | activity.branch = payload.ref; 346 | } 347 | activity.branchLink = gitMethods.getGitHubLink(activity.repo.name + '/tree/' + activity.branch, activity.branch); 348 | } 349 | 350 | // Get the HTML of selected activity type 351 | switch(activity.type){ 352 | case 'CommitCommentEvent': activity.commentLink = gitMethods.getLink(payload.comment.html_url, activity.repo.name + '@' +payload.comment.commit_id.substring(0,6)); 353 | break; 354 | case 'CreateEvent': 355 | break; 356 | case 'DeleteEvent': 357 | break; 358 | case 'ForkEvent': activity.forkLink = gitMethods.getGitHubLink(payload.forkee.html_url, payload.forkee.full_name); 359 | break; 360 | case 'GollumEvent': var page = payload.pages[0]; 361 | activity.actionType = page.action; 362 | activity.wikiMessage = activity.actionType.charAt(0).toUpperCase() + activity.actionType.slice(1) + ' '; 363 | activity.wikiMessage += gitMethods.getLink(page.html_url, page.title); 364 | break; 365 | case 'IssueCommentEvent': activity.commentLink= gitMethods.getLink(payload.comment.html_url, activity.repo.name + '#' +payload.issue.number); 366 | break; 367 | case 'IssuesEvent': activity.issueUrl = gitMethods.getLink(payload.issue.html_url, activity.repo.name + '#' +payload.issue.number); 368 | break; 369 | case 'MemberEvent': activity.memberLink = gitMethods.getGitHubLink(payload.member.login, payload.member.login); 370 | break; 371 | case 'PublicEvent': 372 | break; 373 | case 'PullRequestEvent': activity.mergeRequestUrl = gitMethods.getLink(payload.pull_request.html_url, activity.repo.name + '#' +payload.pull_request.number); 374 | break; 375 | case 'PullRequestReviewCommentEvent': activity.pullCommentUrl= gitMethods.getLink(payload.comment.html_url, activity.repo.name + '#' +payload.pull_request.number); 376 | break; 377 | case 'PushEvent': activity.commitsHtml = gitMethods.getCommitsHTML(activity); 378 | break; 379 | case 'ReleaseEvent': activity.tagLink = gitMethods.getLink(payload.release.html_url, payload.release.tag_name); 380 | activity.zipLink = gitMethods.getLink(payload.release.zipball_url, 'Download Source Code (zip)') 381 | break; 382 | case 'WatchEvent': 383 | break; 384 | } 385 | // Get activity specific message 386 | activity.message = gitMethods.getRenderedHTML(gitTemplates[activity.type], activity); 387 | html += gitMethods.getRenderedHTML(gitTemplates['gitActivityTpl'],activity); 388 | 389 | } 390 | } 391 | // Render created activity HTML to DOM 392 | gitMethods.renderContent(html, options.selector, '.gt-activity-cnt'); 393 | }, 394 | 395 | // Form HTML for commits in PushEvent 396 | getCommitsHTML: function(activity){ 397 | var html = '
    ', 398 | liElement, shaLink, commitMessage, commit, index, 399 | compareLink = '', 400 | payload = activity.payload, 401 | length = payload.commits.length, 402 | shaDiff = payload.before + '...' + payload.head; 403 | 404 | // Get links for 2 or less commit 405 | for(index = 0; index < length; index++){ 406 | if (index>1) break; 407 | commit = payload.commits[index]; 408 | // Create commit li element 409 | liElement = '
  • '; 410 | shaLink = gitMethods.getGitHubLink(activity.repo.name + '/commit/' + commit.sha, commit.sha.substring(0, 6)); 411 | commitMessage = '' + commit.message.substring(0,150) + ''; 412 | liElement += shaLink 413 | liElement += commitMessage; 414 | liElement += '
  • ' 415 | html += liElement; 416 | } 417 | 418 | // Get the diff link between commits 419 | if (length === 2) { 420 | compareLink = gitMethods.getGitHubLink(activity.repo.name + '/compare/' + shaDiff, 'View comparison for these 2 commits »','gt-compare-link'); 421 | } else if (length > 2) { 422 | compareLink = gitMethods.getGitHubLink(activity.repo.name + '/compare/' + shaDiff, (length-2)+' more ' + gitMethods.getPluralWord(length-2,'commit') + ' »','gt-compare-link'); 423 | } 424 | 425 | html += '
' 426 | html += compareLink; 427 | 428 | return html; 429 | }, 430 | 431 | // Utility for asynchronous AJAX calls 432 | getData: function(url, options, callback){ 433 | var data, request; 434 | request = new XMLHttpRequest(); 435 | request.open('GET', url, true); 436 | // Use OAuth token if available 437 | if (options.OAuth) { 438 | request.setRequestHeader('Authorization', 'Token ' + options.OAuth); 439 | } 440 | 441 | request.onload = function(e) { 442 | if (request.status >= 200 && request.status < 400){ 443 | data = JSON.parse(request.responseText); 444 | callback(data, options); 445 | } else { 446 | // Unsuccessful request - invalid username/ lost internet connectivity/ exceeded rate limit/ API URL not found 447 | gitMethods.renderContent(gitMethods.getRenderedHTML(gitTemplates.notFoundTpl, data), options.selector,'.gt-container'); 448 | console.error('An error occurred while connecting to GitHub API.'); 449 | } 450 | }; 451 | 452 | request.onerror = function(e) { 453 | console.error('An error occurred while connecting to GitHub API.'); 454 | }; 455 | 456 | request.send(); 457 | }, 458 | 459 | // Get anchor tag HTML for URL 460 | getLink: function(url, title, cssClass) { 461 | if (!title) 462 | title = url; 463 | if (typeof(cssClass) === 'undefined') 464 | cssClass = ''; 465 | return gitMethods.getRenderedHTML('<%=title%>', { url: url, title: title }); 466 | }, 467 | 468 | // Get anchor tag HTML for non-github URL 469 | getGitHubLink: function(url, title, cssClass) { 470 | if (!title) 471 | title = url; 472 | if (typeof(cssClass) === 'undefined') 473 | cssClass = ''; 474 | return gitMethods.getLink('https://github.com/' + url, title, cssClass); 475 | }, 476 | 477 | // Only for plurals ending with 's'. Yeah! this sucks. 478 | getPluralWord: function (count, word) { 479 | if (count !== 1) return word + 's'; 480 | return word; 481 | }, 482 | 483 | // Get repository language stat HTML 484 | getLanguageHTML: function(data, options){ 485 | var languageData = [], sum = 0, 486 | percentage, languageHtml = ''; 487 | // Get total size and create array which can be sorted by value 488 | _.each(data, function(value, key){ 489 | var data = {}; 490 | data.language = key; 491 | data.size = value; 492 | languageData.push(data); 493 | sum += value; 494 | }); 495 | 496 | // Sort languages by usage in repo 497 | languageData = languageData.sort(function(a, b){return b.size - a.size}); 498 | 499 | // Get HTML for each language 500 | _.each(languageData, function(element){ 501 | percentage = (parseInt(element.size)/sum*100).toFixed(1); 502 | languageHtml +='
'+ 503 | '
'; 504 | }); 505 | 506 | // Render language HTML to the container 507 | gitMethods.renderContent(languageHtml, options.selector,'.gt-repo-lg-stat'); 508 | }, 509 | 510 | // Get random HEX code for color 511 | getRandomColor: function(){ 512 | return Math.random().toString(16).substring(2, 8); 513 | }, 514 | 515 | // Convert milliseconds to time string 516 | millisecondsToStr: function(milliseconds) { 517 | function numberEnding(number) { 518 | return (number > 1) ? 's ago' : ' ago'; 519 | } 520 | var temp = Math.floor(milliseconds / 1000); 521 | 522 | var years = Math.floor(temp / 31536000); 523 | if (years) return years + ' year' + numberEnding(years); 524 | 525 | var months = Math.floor((temp %= 31536000) / 2592000); 526 | if (months) return months + ' month' + numberEnding(months); 527 | 528 | var days = Math.floor((temp %= 2592000) / 86400); 529 | if (days) return days + ' day' + numberEnding(days); 530 | 531 | var hours = Math.floor((temp %= 86400) / 3600); 532 | if (hours) return 'about ' + hours + ' hour' + numberEnding(hours); 533 | 534 | var minutes = Math.floor((temp %= 3600) / 60); 535 | if (minutes) return minutes + ' minute' + numberEnding(minutes); 536 | 537 | var seconds = temp % 60; 538 | if (seconds) return seconds + ' second' + numberEnding(seconds); 539 | 540 | return 'just now'; 541 | }, 542 | 543 | // Render the content to the selector or subSelector 544 | renderContent: function(content, selector, subSelector){ 545 | var selectorDivs = document.querySelectorAll(selector); 546 | 547 | for (var i = 0; i < selectorDivs.length; i++) { 548 | // if subSelector is passed, find it 549 | if (subSelector) { 550 | selectorDiv = selectorDivs[i].querySelector(subSelector); 551 | } else{ 552 | selectorDiv = selectorDivs[i]; 553 | } 554 | selectorDiv.innerHTML = content; 555 | } 556 | 557 | }, 558 | 559 | // Set render limit for activities - default is 30 560 | setLimit: function(value){ 561 | var limit; 562 | if (value !== 'undefined' && gitMethods.checkInteger(limit = parseInt(value, 10))) { 563 | limit = (limit>30)?30:limit; 564 | } else { 565 | limit = 30; 566 | } 567 | return limit; 568 | } 569 | 570 | }; 571 | 572 | 573 | return Github; 574 | })); --------------------------------------------------------------------------------