├── .gitignore
├── favicon.ico
├── images
├── glider.gif
└── glider.4.gif
├── public
├── fonts
│ ├── Hypertext4D.woff
│ └── Hypertext4D.woff2
├── html
│ └── gpgc_redirect.html
├── css
│ └── gpgc_styles.css
└── js
│ └── gpgc_core.js
├── _includes
├── icon-github.html
├── icon-twitter.html
├── icon-twitter.svg
├── icon-github.svg
├── head.html
├── footer.html
├── header.html
└── gpgc_comments.html
├── css
├── title-font.css
└── main.scss
├── _layouts
├── page.html
├── default.html
└── post.html
├── _data
└── gpgc.yml
├── index.html
├── _config.yml
├── scripts
└── mouseScrollTest
│ ├── scrollEventHandler.js
│ └── mouseScrollTest.pde
├── feed.xml
├── about.md
├── _sass
├── _syntax-highlighting.scss
├── _base.scss
└── _layout.scss
├── _posts
├── 2016-06-20-generating-fractal-glider-logo.markdown
├── 2018-02-13-testing-mouse-scroll-wheel.md
└── 2016-06-27-parallel-runners-junit4.markdown
└── _tools
└── gpgcCreateCommentIssue.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .jekyll-metadata
4 | secret
5 |
6 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fractalglider/fractalglider.github.io/HEAD/favicon.ico
--------------------------------------------------------------------------------
/images/glider.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fractalglider/fractalglider.github.io/HEAD/images/glider.gif
--------------------------------------------------------------------------------
/images/glider.4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fractalglider/fractalglider.github.io/HEAD/images/glider.4.gif
--------------------------------------------------------------------------------
/public/fonts/Hypertext4D.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fractalglider/fractalglider.github.io/HEAD/public/fonts/Hypertext4D.woff
--------------------------------------------------------------------------------
/public/fonts/Hypertext4D.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fractalglider/fractalglider.github.io/HEAD/public/fonts/Hypertext4D.woff2
--------------------------------------------------------------------------------
/_includes/icon-github.html:
--------------------------------------------------------------------------------
1 | {% include icon-github.svg %}{{ include.username }}
2 |
--------------------------------------------------------------------------------
/_includes/icon-twitter.html:
--------------------------------------------------------------------------------
1 | {% include icon-twitter.svg %}{{ include.username }}
2 |
--------------------------------------------------------------------------------
/css/title-font.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Hypertext 4D';
3 | src: url('/public/fonts/Hypertext4D.woff2') format('woff2'),
4 | url('/public/fonts/Hypertext4D.woff') format('woff');
5 | font-weight: normal;
6 | font-style: normal;
7 | }
8 |
9 |
10 |
--------------------------------------------------------------------------------
/_layouts/page.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | ---
4 | {{ page.title }}
8 |
subscribe via RSS
22 | 23 |
7 | {{ site.title }}
8 |
9 |
10 |
27 |
28 | No comments
6 |Comments are closed
41 |Could not authenticate OAuth token
GitHub response:
" + checkAuthenticationRequest.responseText + ""; 194 | isRawHtml = true; 195 | } 196 | 197 | showCommentHelpError(helpErrorMessage, isRawHtml); 198 | onAuthenticateUserFailed(); 199 | return; 200 | } 201 | 202 | function onAuthenticateUserFailed() { 203 | var elementsToShow = [ LoginButton ]; 204 | var elementsToHide = [ SubmitButton ]; 205 | var elementsToEnable = [ LoginButton ]; 206 | var elementsToDisable = [ SubmitButton ]; 207 | updateElements(elementsToShow, elementsToHide, elementsToEnable, elementsToDisable); 208 | updateCommenterInformation({ 209 | login: "You", 210 | html_url: "https://github.com/wireddown/ghpages-ghcomments", 211 | avatar_url: "https://raw.githubusercontent.com/wireddown/ghpages-ghcomments/gh-pages/public/apple-touch-icon-precomposed.png" 212 | }); 213 | } 214 | 215 | /* GitHub: Web app login */ 216 | 217 | function loginToGitHub() { 218 | var challengeArray = new Uint32Array(2); 219 | window.crypto.getRandomValues(challengeArray); 220 | StateChallenge = challengeArray[0].toString() + challengeArray[1].toString(); 221 | var data = { 222 | "client_id": gpgc.github_application_client_id, 223 | "scope": "public_repo", 224 | "state": StateChallenge, 225 | "redirect_uri": gpgc.github_application_login_redirect_url 226 | }; 227 | 228 | var urlParameters = Object.keys(data).map(function (key) { 229 | return encodeURIComponent(key) + "=" + encodeURIComponent(data[key]); 230 | }).join("&"); 231 | 232 | window.open( 233 | "https://github.com/login/oauth/authorize?" + urlParameters, 234 | "Log In to GitHub", 235 | "resizable,scrollbars,status,width=1024,height=620" 236 | ); 237 | } 238 | 239 | function handleLogin(code) { 240 | disableElement(LoginButton); 241 | clearCommentHelp(); 242 | showCommentHelpMessage("Finishing login..."); 243 | getTokenUsingCode(code); 244 | } 245 | 246 | function getTokenUsingCode(code) { 247 | getGitHubApiRequestWithCompletion( 248 | gpgc.github_application_code_authenticator_url + code, 249 | /* data: */ null, 250 | /* accessToken: */ null, 251 | /* onPreRequest: */ noop, 252 | onTokenRetrieved, 253 | onRetrieveTokenFailed 254 | ); 255 | } 256 | 257 | function onTokenRetrieved(retrieveTokenRequest) { 258 | var tokenResponse = JSON.parse(retrieveTokenRequest.responseText); 259 | if (tokenResponse.token !== undefined) { 260 | AccessToken = tokenResponse.token; 261 | persistToken(); 262 | } else { 263 | onRetrieveTokenFailed(retrieveTokenRequest); 264 | } 265 | 266 | authenticateUser(); 267 | } 268 | 269 | function onRetrieveTokenFailed(retrieveTokenRequest) { 270 | enableElement(LoginButton); 271 | clearCommentHelp(); 272 | showFatalError("onRetrieveTokenFailed: \n\n" + retrieveTokenRequest.responseText); 273 | } 274 | 275 | /* GitHub: Search for comment issue */ 276 | 277 | function findAndCollectComments(repositoryID, issueTitle) { 278 | var safeQuery = encodeURI(issueTitle); 279 | var seachQueryUrl = "https://api.github.com/search/issues?q=" + safeQuery + "+repo:" + repositoryID + "+type:issue+in:title"; 280 | getGitHubApiRequestWithCompletion( 281 | seachQueryUrl, 282 | /* data: */ null, 283 | AccessToken, 284 | /* onPreRequest: */ noop, 285 | onSearchComplete, 286 | onSearchError 287 | ); 288 | } 289 | 290 | function onSearchComplete(searchRequest) { 291 | var searchResults = JSON.parse(searchRequest.responseText); 292 | if (searchResults.total_count === 1) { 293 | var shouldQueryComments = !isIssueMuted(searchResults.items[0].labels); 294 | if (shouldQueryComments) { 295 | IssueUrl = searchResults.items[0].html_url; 296 | CommentsUrl = searchResults.items[0].comments_url; 297 | insertIssueLink(IssueUrl); 298 | getGitHubApiRequestWithCompletion( 299 | CommentsUrl, 300 | /* data: */ null, 301 | AccessToken, 302 | /* onPreRequest: */ noop, 303 | onQueryComments, 304 | onQueryCommentsError 305 | ); 306 | } else { 307 | disableNewCommentForm(); 308 | } 309 | } else { 310 | onSearchError(searchRequest); 311 | } 312 | } 313 | 314 | function insertIssueLink(issueUrl) { 315 | var issueLinkMessage = "
Comments to this post can also be created and viewed on GitHub.
"; 316 | document.getElementById("gpgc_issue_link").innerHTML = issueLinkMessage; 317 | } 318 | 319 | function onSearchError(searchRequest) { 320 | if (gpgc.enable_diagnostics) { 321 | var searchErrorMessage = ""; 322 | if (searchRequest.status !== 200) { 323 | searchErrorMessage = "Could not search GitHub repository " + gpgc.repo_id + ".
GitHub response:
" + searchRequest.responseText + "
Check:
repo_owner in _data/gpgc.yml for typos.repo_name in _data/gpgc.yml for typos.Could not find comment issue with the title " + gpgc.issue_title + " in the repository " + gpgc.repo_id + ".
Check:
title front matter for this post: " + gpgc.page_path + ".repo_name in _data/gpgc.yml matches the repository for this site.git push for other error messages if the git hooks are installed.Verify your site's configuration with the setup instructions and refer to the verbose usage for step-by-step details.
Contact ghpages-ghcomments for more help.
"; 335 | 336 | ErrorDiv.innerHTML += allMessagesHtml; 337 | showElement(ErrorDiv); 338 | } 339 | } else { 340 | if (searchRequest.status === 401) { 341 | AccessToken = ""; 342 | findAndCollectComments(gpgc.repo_id, gpgc.issue_title); 343 | } else { 344 | showFatalError("onSearchError: \n\n" + searchRequest.responseText); 345 | } 346 | } 347 | } 348 | 349 | function isIssueMuted(labelsArray) { 350 | for (var i = 0; i < labelsArray.length; i++) { 351 | if (labelsArray[i].name === "GPGC Muted") { 352 | return true; 353 | } 354 | } 355 | 356 | return false; 357 | } 358 | 359 | /* GitHub: Retrieve comments */ 360 | 361 | function onQueryComments(commentRequest) { 362 | CommentsArray = CommentsArray.concat(JSON.parse(commentRequest.responseText)); 363 | var commentsPages = commentRequest.getResponseHeader("Link"); 364 | if (commentsPages) { 365 | var commentsLinks = commentsPages.split(","); 366 | for (var i = 0; i < commentsLinks.length; i++) { 367 | if (commentsLinks[i].search('rel="next"') > 0) { 368 | var linkStart = commentsLinks[i].search("<"); 369 | var linkStop = commentsLinks[i].search(">"); 370 | var nextLink = commentsLinks[i].substring(linkStart + 1, linkStop); 371 | getGitHubApiRequestWithCompletion( 372 | nextLink, 373 | /* data: */ null, 374 | AccessToken, 375 | /* onPreRequest: */ noop, 376 | onQueryComments, 377 | onQueryCommentsError); 378 | return; 379 | } 380 | } 381 | updateCommentsAndActions(CommentsArray); 382 | } 383 | else { 384 | updateCommentsAndActions(CommentsArray); 385 | } 386 | } 387 | 388 | function onQueryCommentsError(commentRequest) { 389 | showFatalError("onQueryCommentsError: \n\n" + commentRequest.responseText); 390 | } 391 | 392 | /* GitHub: Render markdown */ 393 | 394 | function renderMarkdown(markdown) { 395 | renderUrl = "https://api.github.com/markdown"; 396 | markdownBundle = { 397 | text: markdown, 398 | mode: "gfm", 399 | context: gpgc.repo_id 400 | }; 401 | postGitHubApiRequestWithCompletion( 402 | renderUrl, 403 | JSON.stringify(markdownBundle), 404 | AccessToken, 405 | onRenderRequestStarted, 406 | onMarkdownRendered, 407 | onMarkdownRenderError 408 | ); 409 | } 410 | 411 | function onRenderRequestStarted() { 412 | PreviewDiv.innerHTML = "Rendering...
"; 413 | } 414 | 415 | function onMarkdownRendered(renderRequest) { 416 | var renderedHtml = renderRequest.responseText; 417 | PreviewDiv.innerHTML = renderedHtml; 418 | } 419 | 420 | function onMarkdownRenderError(renderRequest) { 421 | var helpErrorMessage = "Sorry, something surprising happened. Please try again."; 422 | var isRawHtml = false; 423 | if (gpgc.enable_diagnostics) { 424 | helpErrorMessage = "Could not render comment markdown
GitHub response:
" + renderRequest.responseText + ""; 425 | isRawHtml = true; 426 | } 427 | 428 | showCommentHelpError(helpErrorMessage, isRawHtml); 429 | return; 430 | } 431 | 432 | /* GitHub: Post comment */ 433 | 434 | function postComment() { 435 | if (CommentMarkdown.value.length === 0) { 436 | showCommentHelpError("Sorry, but your comment is empty. Please try again.", /* isRawHtml: */ false); 437 | return; 438 | } else { 439 | clearCommentHelp(); 440 | } 441 | 442 | var createCommentJson = { body: CommentMarkdown.value }; 443 | postGitHubApiRequestWithCompletion( 444 | CommentsUrl, 445 | JSON.stringify(createCommentJson), 446 | AccessToken, 447 | onPostCommentStarted, 448 | onCommentPosted, 449 | onPostCommentError 450 | ); 451 | } 452 | 453 | function onPostCommentStarted() { 454 | showCommentHelpMessage("Posting comment..."); 455 | } 456 | 457 | function onCommentPosted(postCommentRequest) { 458 | var commentInformation = JSON.parse(postCommentRequest.responseText); 459 | var newComment = formatComment(commentInformation.user.avatar_url, commentInformation.user.html_url, commentInformation.user.login, commentInformation.body_html, commentInformation.updated_at); 460 | AllCommentsDiv.innerHTML += newComment; 461 | showAllComments(); 462 | updateCommentFormMode(WriteMode, /* reset: */ true); 463 | clearCommentHelp(); 464 | } 465 | 466 | function onPostCommentError(postCommentRequest) { 467 | var helpErrorMessage = "Sorry, something surprising happened. Please try again."; 468 | var isRawHtml = false; 469 | if (gpgc.enable_diagnostics) { 470 | helpErrorMessage = "
Could not create a new comment
GitHub response:
" + postCommentRequest.responseText + ""; 471 | isRawHtml = true; 472 | } 473 | 474 | showCommentHelpError(helpErrorMessage, isRawHtml); 475 | } 476 | 477 | /* Comments */ 478 | 479 | function updateCommentsAndActions(allComments) { 480 | var elementsToShow = []; 481 | var elementsToHide = []; 482 | 483 | if (allComments.length === 0) { 484 | elementsToShow.push(NoCommentsDiv); 485 | } else { 486 | var allCommentsHtml = formatAllComments(CommentsArray); 487 | AllCommentsDiv.innerHTML = allCommentsHtml + AllCommentsDiv.innerHTML; 488 | 489 | var commentOrComments = allComments.length === 1 ? "Comment" : "Comments"; 490 | ShowCommentsButton.innerHTML = "Show " + allComments.length + " " + commentOrComments; 491 | 492 | if (typeof gpgc.use_show_action === "boolean" && gpgc.use_show_action) { 493 | elementsToShow.push(ActionsDiv); 494 | elementsToHide.push(AllCommentsDiv); 495 | } else { 496 | elementsToHide.push(ActionsDiv); 497 | elementsToShow.push(AllCommentsDiv); 498 | } 499 | } 500 | 501 | updateElements(elementsToShow, elementsToHide, /* elementsToEnable: */ null, /* elementsToDisable: */ null); 502 | } 503 | 504 | function formatAllComments(allComments) { 505 | var allCommentsHtml = ""; 506 | for (var i = 0; i < allComments.length; i++) { 507 | var user = allComments[i].user; 508 | allCommentsHtml += formatComment(user.avatar_url, user.html_url, user.login, allComments[i].body_html, allComments[i].updated_at); 509 | } 510 | 511 | return allCommentsHtml; 512 | } 513 | 514 | function formatComment(userAvatarUrl, userHtmlUrl, userLogin, commentBodyHtml, commentTimeStamp) { 515 | var commentDate = new Date(commentTimeStamp); 516 | var shortMonth = ShortMonthForIndex[commentDate.getMonth()]; 517 | var commentHtml = "
" + message + "
"; 548 | } 549 | HelpMessageDiv.classList.add(cssClassToAdd); 550 | HelpMessageDiv.classList.remove(cssClassToRemove); 551 | showElement(HelpMessageDiv); 552 | } 553 | 554 | function clearCommentHelp() { 555 | HelpMessageDiv.innerHTML = ""; 556 | HelpMessageDiv.classList.remove("gpgc-help-message"); 557 | HelpMessageDiv.classList.remove("gpgc-help-error"); 558 | hideElement(HelpMessageDiv); 559 | } 560 | 561 | function showFatalError(internalMessage) { 562 | var nextStepMessage = "If you're the site owner, please set enable_diagnostics to true in _data/gpgc.yml to see more details.
If you're the site owner, please contact ghpages-ghcomments for help.
Internal message
" + internalMessage + ""; 565 | } 566 | 567 | ErrorDiv.innerHTML += "
Something surprising happened.
" + nextStepMessage; 568 | showElement(ErrorDiv); 569 | } 570 | 571 | /* Visual element manipulation */ 572 | 573 | function updateElements(elementsToShow, elementsToHide, elementsToEnable, elementsToDisable) { 574 | if (elementsToShow !== null) { showElements(elementsToShow); } 575 | if (elementsToHide !== null) { hideElements(elementsToHide); } 576 | if (elementsToEnable !== null) { enableElements(elementsToEnable); } 577 | if (elementsToDisable !== null) { disableElements(elementsToDisable); } 578 | } 579 | 580 | function updateElementVisibility(element, makeVisible) { 581 | if (makeVisible) { 582 | element.classList.remove("gpgc-hidden"); 583 | } else { 584 | element.classList.add("gpgc-hidden"); 585 | } 586 | } 587 | 588 | function showElement(element) { 589 | updateElementVisibility(element, /* makeVisible: */ true); 590 | } 591 | 592 | function showElements(elementList) { 593 | for (var i = 0; i < elementList.length; i++) { 594 | showElement(elementList[i]); 595 | } 596 | } 597 | 598 | function hideElement(element) { 599 | updateElementVisibility(element, /* makeVisible: */ false); 600 | } 601 | 602 | function hideElements(elementList) { 603 | for (var i = 0; i < elementList.length; i++) { 604 | hideElement(elementList[i]); 605 | } 606 | } 607 | 608 | function updateElementInteractivity(element, makeInteractive) { 609 | if (makeInteractive) { 610 | element.disabled = false; 611 | } else { 612 | element.disabled = true; 613 | } 614 | } 615 | 616 | function enableElement(elementToEnable) { 617 | updateElementInteractivity(elementToEnable, /* makeInteractive: */ true); 618 | } 619 | 620 | function enableElements(elementList) { 621 | for (var i = 0; i < elementList.length; i++) { 622 | enableElement(elementList[i]); 623 | } 624 | } 625 | 626 | function disableElement(elementToDisable) { 627 | updateElementInteractivity(elementToDisable, /* makeInteractive: */ false); 628 | } 629 | 630 | function disableElements(elementList) { 631 | for (var i = 0; i < elementList.length; i++) { 632 | disableElement(elementList[i]); 633 | } 634 | } 635 | 636 | /* Async web requests */ 637 | 638 | function getGitHubApiRequestWithCompletion(url, data, accessToken, onPreRequest, onSuccess, onError) { 639 | doGitHubApiRequestWithCompletion("GET", url, data, accessToken, onPreRequest, onSuccess, onError); 640 | } 641 | 642 | function postGitHubApiRequestWithCompletion(url, data, accessToken, onPreRequest, onSuccess, onError) { 643 | doGitHubApiRequestWithCompletion("POST", url, data, accessToken, onPreRequest, onSuccess, onError); 644 | } 645 | 646 | function doGitHubApiRequestWithCompletion(method, url, data, accessToken, onPreRequest, onSuccess, onError) { 647 | var gitHubRequest = new XMLHttpRequest(); 648 | gitHubRequest.open(method, url, /* async: */ true); 649 | 650 | if (accessToken !== null && accessToken !== "") { 651 | gitHubRequest.setRequestHeader("Authorization", "token " + accessToken); 652 | } 653 | 654 | gitHubRequest.setRequestHeader("Accept", "application/vnd.github.v3.html+json"); 655 | gitHubRequest.onreadystatechange = function () { onRequestReadyStateChange(gitHubRequest, onSuccess, onError); }; 656 | 657 | onPreRequest(); 658 | gitHubRequest.send(data); 659 | } 660 | 661 | function noop() { 662 | } 663 | 664 | function onRequestReadyStateChange(httpRequest, onSuccess, onError) { 665 | if (httpRequest.readyState !== 4) { return; } 666 | if (httpRequest.status === 200 || httpRequest.status === 201) { 667 | onSuccess(httpRequest); 668 | } else { 669 | onError(httpRequest); 670 | } 671 | } 672 | 673 | /* Diagnostics */ 674 | 675 | function verifyCss() { 676 | var css = document.styleSheets; 677 | var foundCssInHead = false; 678 | var fetchedCss = false; 679 | for (var i = 0; i < css.length; i++) { 680 | if (css[i].href.match("gpgc_styles.css")) { 681 | foundCssInHead = true; 682 | if (css[i].cssRules.length > 0) { 683 | fetchedCss = true; 684 | } 685 | break; 686 | } 687 | } 688 | 689 | var missingCssMessage = ""; 690 | if (! foundCssInHead) { 691 | missingCssMessage = "gpgc_styles.css is not in the <head> element.
Add a <link> element to _includes/head.hml.
Could not retrieve gpgc_styles.css from your site.
Check _includes/head.hml for typos.
The following settings are missing:
"; 705 | var stringPropertyNames = ["site_url", "page_path", "issue_title", "repo_id", "github_application_client_id", "github_application_code_authenticator_url", "github_application_login_redirect_url"]; 706 | var booleanPropertyNames = ["new_comments_disabled", "use_show_action", "enable_diagnostics"]; 707 | var missingPropertyCounter = 0; 708 | 709 | for (var index in stringPropertyNames) { 710 | var stringProperty = stringPropertyNames[index]; 711 | if (gpgc[stringProperty].length < 1) { 712 | if (missingPropertyCounter == 0) { 713 | missingPropertyMessage = missingPropertyMessage + "Verify your site's configuration with the setup instructions and refer to the verbose usage for step-by-step details.
Contact ghpages-ghcomments for more help.
"; 742 | 743 | ErrorDiv.innerHTML += allMessagesHtml; 744 | showElement(ErrorDiv); 745 | } 746 | } 747 | --------------------------------------------------------------------------------