Skip to content

Instantly share code, notes, and snippets.

@frontendecoder
Created March 7, 2017 17:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frontendecoder/319c53080567b43eae0d7270b0b6fbbf to your computer and use it in GitHub Desktop.
Save frontendecoder/319c53080567b43eae0d7270b0b6fbbf to your computer and use it in GitHub Desktop.
Github API tech finder
'use strict';
// Usage
// Create root HTML tag: <div id="app"></div>
// Create widget instance: var app = new GridGitHubJS('app');
// or Create widget with search params (keyword, technology): var app = new GridGitHubJS('app', 'map', 'javascript');
class GridGitHubJS {
constructor(rootElId, keyword='', tech='') {
// Private data
this.data = {};
this.curPageNum = 1;
this.itemsPerGage = 30;
this.rowCount = 0;
this.searchKeyword = keyword;
this.searchTech = tech;
this.apiUrl = 'https://api.github.com/search/repositories';
// https://api.github.com/search/repositories?q=map+language:javascript&sort=stars&order=desc
const template = `
<div class="gridsterContainer">
<div class="searchBox">
<input type="text" id="searchWordGrst" value="${ this.searchKeyword }" placeholder="Keyword"/ >
<input type="text" id="searchTechGrst" value="${ this.searchTech }" placeholder="Technology" />
<button id="searchBtnGrst">Search</button>
</div>
<div class="stats">
<div class="total">Total items: <span id="rowCount"></span></div>
<div class="pager">
<button id="prevPageBtn">Prev</button>
<span>
<span id="curPageNum"></span>/<span id="maxPageNum"></span>
</span>
<button id="nextPageBtn">Next</button>
</div>
</div>
<table class="gridster">
<thead>
<tr>
<th>Index</th>
<th>Name</th>
<th>Owner</th>
<th>Url</th>
<th>Description</th>
<th>Stars</th>
<th>Detail</th>
</tr>
</thead>
<tbody id="gridsterTableBody"></tbody>
</table>
</div>
<div id="gridsterDetailPopup" class="gridsterDetailPopup">
<div class="body"></div>
<div class="fog"></div>
</div>
`;
// Add template to dom
document.getElementById(rootElId).innerHTML = template;
// Init
this.searchWordEl = document.getElementById('searchWordGrst');
this.searchTechEl = document.getElementById('searchTechGrst');
this.tableBody = document.getElementById('gridsterTableBody');
this.popupEl = document.getElementById('gridsterDetailPopup');
this.popupBody = this.popupEl.querySelector('.body');
this.rowCountEl = document.getElementById('rowCount');
this.curPageNumEl = document.getElementById('curPageNum');
this.maxPageNumEl = document.getElementById('maxPageNum');
const self = this;
// Add search button click event listener
document.getElementById('searchBtnGrst').addEventListener('click', (e)=>{
self.searchBtnClickHandler(self);
}, false);
// Add button click event listener to tablebody for show popup
this.tableBody.addEventListener('click', (e)=>{
self.tableBodyClickHandler(e, self);
}, false);
// Add Close popup event listener
this.popupEl.querySelector('.fog').addEventListener('click', ()=>{
self.hideDetailPopup();
}, false);
// Pagination
document.getElementById('prevPageBtn').addEventListener('click', (e)=>{
self.prevPage(self);
}, false);
document.getElementById('nextPageBtn').addEventListener('click', (e)=>{
self.nextPage(self);
}, false);
// Launch. Fetch data
this.fetchData(self);
}
fillTable(self, data) {
let tableRowAll = '',
tableBodyTemplate = '';
const itemsLen = data.items.length;
for (let i=0; i < itemsLen; i++) {
let item = data.items[i],
index = (self.curPageNum * self.itemsPerGage - self.itemsPerGage) + i + 1;
tableBodyTemplate = `<tr>
<td>${ index }</td>
<td>${ item.name }</td>
<td>${ item.owner.login }</td>
<td><a href="${ item.html_url }" target="_blank" title="${ item.html_url }">URL</a></td>
<td>${ item.description }</td>
<td>${ item.stargazers_count }</td>
<td><button class="showDetailPopup" data-idx="${i}">Detail</button></td>
</tr>
`;
tableRowAll += tableBodyTemplate;
}
this.tableBody.innerHTML = tableRowAll;
}
fetchData(self) {
let fullQuery = self.apiUrl
+'?q='+ self.searchKeyword
+'+language:'+ self.searchTech
+ '&sort=stars&order=desc'
+ '&page='+self.curPageNum
+ '&per_page='+self.itemsPerGage;
fetch(fullQuery)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
}).then((data) => {
self.data = data;
self.rowCount = data.total_count;
self.itemsPerGage = data.items.length;
self.fillTable(self, data);
self.updateStats(self);
}).catch((error) => {
console.log(error);
});
}
searchBtnClickHandler(self) {
self.searchKeyword = self.searchWordEl.value;
self.searchTech = self.searchTechEl.value;
self.curPageNum = 1;
self.fetchData(self);
}
tableBodyClickHandler(e, self) {
if (e.target.className === 'showDetailPopup') {
const idx = e.target.getAttribute('data-idx');
let itemData= JSON.stringify(self.data.items[idx], null, '<br>');
self.popupBody.innerHTML = itemData;
// self.popupBody.textContent = itemData;
self.showDetailPopup();
}
}
showDetailPopup() {
this.popupEl.classList.add('show');
}
hideDetailPopup() {
this.popupEl.classList.remove('show');
}
updateStats(self) {
self.rowCountEl.textContent = self.rowCount;
self.curPageNumEl.textContent = self.curPageNum;
self.maxPageNumEl.textContent = parseInt(self.rowCount / self.itemsPerGage);
}
prevPage(self) {
if (self.curPageNum <= 1) return false;
self.curPageNum--;
self.fetchData(self);
}
nextPage(self) {
if (self.curPageNum >= self.maxPageNum) return false;
self.curPageNum++;
self.fetchData(self);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment