Skip to content

Instantly share code, notes, and snippets.

@dereckson
Created March 20, 2017 23:11
Show Gist options
  • Save dereckson/83d62a8b729f260d23e990426207047c to your computer and use it in GitHub Desktop.
Save dereckson/83d62a8b729f260d23e990426207047c to your computer and use it in GitHub Desktop.
Code to parse a JSON document, decorate with relevant links and print a server log
"use strict";
/* -------------------------------------------------------------
Nasqueron infrastructure
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Project: Nasqueron
Author: Sébastien Santoro aka Dereckson
Dependencies: jQuery
Filename: app.js
Licence: CC-BY 4.0, MIT, BSD-2-Clause (multi-licensing)
------------------------------------------------------------- */
/* -------------------------------------------------------------
Table of contents
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
:: Servers log
:: Code to run when document is ready
*/
var ServersLog = function ServersLog(url, container) {
var serversLog = {
///
/// Private properties
///
/**
* A JQuery selector expression to a DOM element to publish the log in.
*
* @var string
*/
container: "",
/**
* The URL to fetch the log.
*
* @var string
*/
url: "",
/**
* The log entries fetched.
*
* @var array
*/
logEntries: [],
///
/// Constructor
///
/**
* Initializes an instance of this object.
*
* @param url The URL to the log
* @param container The DOM element JQuery selector where to write
*/
load: function load(url, container) {
this.url = url;
this.container = container;
this.refreshData();
},
///
/// Main methods
///
/**
* Fetches log entries. That will trigger an UI refresh once fetched.
*/
refreshData: function refreshData() {
this.fetchLogEntries();
},
/**
* Refreshes the UI from the content in logEntries array.
*/
refreshUI: function refreshUI() {
$(this.container).html(this.formatEntries());
},
///
/// Data helper methods
///
/**
* Fetches the log entries at the log URL, fills logEntries array,
* refreshes the UI.
*/
fetchLogEntries: function fetchLogEntries() {
$.getJSON(this.url, function (data) {
serversLog.logEntries = data.reverse(); // Log is chronological.
serversLog.refreshUI();
});
},
///
/// UI helper methods
///
formatEntries: function formatEntries() {
var currentDate = "";
var currentMonth = "";
var entries = "";
for (var i = 0; i < this.logEntries.length; i++) {
var entry = this.logEntries[i];
var date = this.getDate(entry.date);
if (date != currentDate) {
// Month heading
var month = this.getMonth(entry.date);
if (month != currentMonth) {
entries += this.formatMonthHeadings(entry.date);
currentMonth = month;
}
// Day heading
entries += this.formatDateHeadings(date);
currentDate = date;
}
entries += this.formatEntry(entry);
}
return entries;
},
formatEntry: function formatEntry(entry) {
var format = "<p class=\"log-entry\">\n <span class=\"log-component secondary label\">%%component%%</span>\n <span class=\"log-time\">%%date%%</span>\n <span class=\"log-emitter\">%%emitter%%</span>:\n <span class=\"log-message\">%%message%%</span>\n </p>";
return format.replace("%%component%%", entry.component).replace("%%date%%", this.getTime(entry.date)).replace("%%emitter%%", entry.emitter).replace("%%message%%", this.formatMessage(entry.entry));
},
///
/// Formats date headings
///
/**
* The month names.
*
* @var array
*/
monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
/**
** Gets a day headings element.
*
* @param date The date to print
* @returns {string} The day heading
*/
formatDateHeadings: function formatDateHeadings(date) {
return '<h3>' + date + '</h3>';
},
/**
* Gets a month heading element.
*
* @param timestamp The date to parse
* @returns {string} The month heading
*/
formatMonthHeadings: function formatMonthHeadings(timestamp) {
var date = new Date(timestamp);
var month = this.monthNames[date.getMonth()];
return "<h2>" + month + "</h2>";
},
///
/// Format messages helper functions
///
/**
* @var array
*/
messageDecorators: [{
// SHA-1 Git commit hashes
re: /\b([0-9a-f]{7,40})\b/g,
/**
* Callback method to linkify when needed a SHA-1 hash.
*
* @param match The expression matched by the regexp
* @param p1 The SHA-1 hash candidate
* @param offset The position p1 has been found
* @param string The full string p1 has been found
* @returns {string}
*/
replaceBy: function replaceBy(match, p1, offset, string) {
if (!serversLog.isHash(p1)) {
return p1;
}
return '<a href="https://devcentral.nasqueron.org/search/?query=%1">%1</a>'.replace(/%1/g, p1);
}
}, {
// Tasks, reviews and pastes
re: /\b([TDP][0-9]{1,6}(\#[0-9]{1,10})?)\b/g,
replaceBy: '<a href="https://devcentral.nasqueron.org/$1">$1</a>'
}, {
// Repositories callsigns
re: /\br([A-Z]{3,32})\b/g,
replaceBy: '<a rel="repository" href="https://devcentral.nasqueron.org/diffusion/$1/">r$1</a>'
}, {
// Commits with callsigns
re: /\br([A-Z]{3,32}[0-9a-f]{7,40})\b/g,
replaceBy: '<a rel="commit" href="https://devcentral.nasqueron.org/r$1">r$1</a>'
}, {
// Code (or SQL query parameter)
re: /`(.*?)`/g,
replaceBy: '<code>$1</code>'
}],
/**
* Whitelist of known hexadecimal words.
*
* @var array
*/
hexadecimalKnownWord: ["added", "ed25519"],
/**
* Determines if an expression matches a whitelisted hexadecimal word.
*
* @param word The word to check
* @returns {boolean}
*/
isHexadecimalKnownWord: function isHexadecimalKnownWord(word) {
return this.hexadecimalKnownWord.indexOf(word) > -1;
},
/**
* Determines if the specified expression is probably an hash.
*
* An hash is anything hexadecimal with at least one digit < 10
* and one digit > 9 (A-F), not matching known vocabulary.
*
* @param hash
* @returns {boolean}
*/
isHash: function isHash(hash) {
if (this.isHexadecimalKnownWord(hash)) {
return false;
}
if (/^\d+$/.test(hash) || /^[a-z]+$/i.test(hash)) {
// Contains only letter or digits,
// so not a good hash candidate.
return false;
}
return true;
},
formatMessage: function formatMessage(message) {
for (var i = 0; i < this.messageDecorators.length; i++) {
var decorator = this.messageDecorators[i];
message = message.replace(decorator.re, decorator.replaceBy);
}
return message;
},
///
/// Date and time stuff
///
pad: function pad(number) {
if (number < 10) {
return '0' + number;
}
return number;
},
getDate: function getDate(timestamp) {
var date = new Date(timestamp);
return date.getUTCFullYear() + '-' + this.pad(date.getUTCMonth() + 1) + '-' + this.pad(date.getUTCDate());
},
getTime: function getTime(timestamp) {
var date = new Date(timestamp);
return this.pad(date.getUTCHours()) + ':' + this.pad(date.getUTCMinutes());
},
getMonth: function getMonth(timestamp) {
var date = new Date(timestamp);
return date.getUTCMonth();
}
};
typeof container === 'string' && serversLog.load(url, container);
return serversLog;
};
/* -------------------------------------------------------------
Code to run when document is ready
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
$(document).ready(function () {
$(document).foundation();
new ServersLog("https://api.nasqueron.org/servers-log/all.json", "#log");
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment