Skip to content

Instantly share code, notes, and snippets.

@justsml
Created September 12, 2015 03:18
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 justsml/dcc787630a86a5a1eca7 to your computer and use it in GitHub Desktop.
Save justsml/dcc787630a86a5a1eca7 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href='http://fonts.googleapis.com/css?family=Roboto:400,700' rel='stylesheet' type='text/css'>
<link href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css' rel='stylesheet' type='text/css'>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js'></script>
<script>
'use strict'
var Utils = {
escapeHtml: function _escapeHtml(s) {// Prevent code injection and rendering issues
return String(s).replace(/&/g,'&amp;').replace(/>/g,'&gt;').replace(/</g,'&lt;');
}
}
function Panel(opts) {
return ['<div class="panel">',
' <div class="panel-heading">',
' <h4>',
' <span class="status"><b class="fa fa-', opts.icon, '"></b></span>',
' <span class="name">', Utils.escapeHtml(opts.title), '</span>',
' </h4>',
' </div>',
' <div class="panel-body">',
(opts.trustedBody || Utils.escapeHtml(opts.body)),
' </div>',
' <div class="panel-footer">', ICONS_HTML, '</div>',
'</div>'].join('');
}
function ConfigurationController(element) {
if ( !element ) { throw new Error('Cannot create ConfigurationController: Element Required');}
var self = this,
_limit = 2,
apiUrl = "http://somedomain/download/request?host=";
// Expose Public method(s)
this.load = load;
this.render = render;
function load(limit) {
reset();
limit = parseInt(limit || 2);
_limit = limit;
// Attempt ajax call; on fail: use dummy data
$.ajax(apiUrl + encodeURIComponent(limit))
.success(render)
.fail(errorHandler)
.always(function() {
console.log('http.always', arguments);
if (element.children().length === 0) {
errorHandler();
}
});
}
function render(data) {
// Do basic response check
if (!data || !data.configurations || !Array.isArray(data.configurations)) {
console.error(new Error('Invalid Server response'));
return render(dummyData(_limit));
} else if (data.configurations.length === 0) {
}
reset();
// render out config
if (data.configurations && data.configurations.length > 1) {
/*
Cute, but inefficient (returns an in-memory transform of an already-big array, only bigger. finally serially call append() for each returned renderItem):
data.configurations
.map(renderItem)
.map(element.append);*/
data.configurations
//let's use `this` binding to pass a callback FN for the resulting DOM/jQuery element
//.map(renderItem, element)
.map(renderItem, function(el) {
element.append(el);
});
//.map(element.append);
} else {
errorHandler('Failed to render');
}
}
function reset() {
// reset UI
element.children().remove();
return element;
}
function renderItem(obj, index, list) {
var callback = typeof this === 'function' ? this : false;
// This could use document create fragment, possible speed boost
var randStatus = STATUS_ICONS[Math.floor(Math.random() * STATUS_ICONS.length)];
// 20% of the time, pick random status icon, in all other cases pick the 'good' check icon.
var statusIcon = (index % 20 === 0 ? randStatus : STATUS_ICONS[0]);
var itemPanel = Panel({icon: statusIcon,
title: obj.name,
trustedBody: [
' <div><b class="fa fa-desktop"></b> host: ', Utils.escapeHtml(obj.hostname), '</div>',
' <div><b class="fa fa-link"></b> port: ', Utils.escapeHtml(obj.port), '</div>',
' <div><b class="fa fa-user"></b> user: ', Utils.escapeHtml(obj.username), '</div>'].join('\n') });
itemPanel = $(itemPanel);
return (typeof(callback) === 'function' ? callback(itemPanel) : itemPanel);
}
function errorHandler(err) {
console.log('errorHandler', arguments);
// reset();
element.append('<div class="panel tile has-error">Failed</div>');
// Load dummy data
render(MOCK_DATA);
}
}
$(document).ready(function _onLoad() {
var ctrl = new ConfigurationController($('#configurationList'));
ctrl.load();
var limitBtns = $('.btn[data-limit], .btn[limit]').click(function(e) {
var el = $(e);
ctrl.load(parseInt(el.attr('limit'), null));
});
});
// Mock/dummy helpers
function dummyData(limit) {
return {configurations: Array.apply(0, Array(limit || 100)).map(function (x, y) {
var seq = y + 1;
return getFakeSite(); })};
}
// Using jQuery + native JS/DOM code
const SVCS_ICONS = {'ftp': 'file', 'ntp': 'clock', 'web': 'globe', 'ldap': 'user', 'fw': 'lock'};
const SVCS = Object.keys(SVCS_ICONS);
const USERS = ['alice', 'bob', 'carol', 'dan', 'eve'];
const STATUS_ICONS = ['check', 'thumbs-up', 'fire', 'exclamation-circle'];
const TOOLBAR_ICONS = ['line-chart', 'map'];
const ICONS_HTML = TOOLBAR_ICONS
.map(getIconHtml)
.join('');
const MOCK_DATA = dummyData(500);// NOTE: way slower with animation/transitions enabled
// fa-exclamation-circle
function getIconHtml(ico) {return '<b title="' + Utils.escapeHtml(ico) + '" class="fa fa-' + Utils.escapeHtml(ico) + '"></b>';}
function rand(limit) {return parseInt(Math.random() * limit);}
function getFakeSite() {
var hostId = rand(1001);
var svc = SVCS[rand(SVCS.length)];
return {
name: svc + hostId + '-nessus.com',
hostname: 'nessus-' + svc + '-' + hostId,
port: rand(1000) + 100,
username: USERS[rand(USERS.length)],
service: svc
}
}
</script>
<style>
body {
font-family: Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif;
margin: 0px;
padding: 78px 0px 0px 0px;
/* for fixed heading */
/*padding-top: 67px;*/
}
h1 { margin: 4px 2px; }
h4 { margin: 2px 2px; }
.page-header-fixed {
position: fixed;
top: 0px;
left: 0;
right: 0;
}
/* Define a bootstrap-ish minimal style
---- 425363 */
.text-success { color: #94c0e9; }
.text-info { color: #0071ce; }
.text-warning { color: #ff8300; }
.page-header {
/*line-height: 48px;*/
transition: all 0.2s;
color: #FFF;
background: #425363;
padding: 6px 10px;
margin-bottom: 10px;
box-shadow: rgba(0, 0, 0, 0.90) 5px 1px 4px 0px;
}
.panel {
transition: all 0.25s ease-in;
box-sizing: border-box;
color: #666666;
background-color: #FFF;
border: 1px solid #DEDEDE;
border-top: none;
border-radius: 2px 2px 2px 2px;
font-family: Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 15px;
line-height: 20px;
margin: 8px 2px;
}
.panel-heading {
cursor: pointer;
background-color: #0071ce;
transition: background-color 0.25s ease-in, color 0.25s ease-in;
border-color: #2196F3;
border-top-left-radius: 2px 2px 0px 0px;
box-sizing: border-box;
color: #fff;
display: block;
font-family: Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 18px;
font-weight: 400;
line-height: 19px;
padding: 10px 15px 10px 15px;
}
.panel-body {
transition: background-color 0.25s ease-in, color 0.25s ease-in;
padding: 15px;
}
/*.btn {
border: none;
font-family: inherit;
cursor: pointer;
padding: 25px 80px;
display: inline-block;
margin: 15px 30px;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 700;
outline: none;
position: relative;
}*/
.status .fa {
font-size: 22px;
margin: 6px;
}
.panel-footer {
width: 100%;
text-align: right;
}
.panel-footer .fa {
font-size: 18px;
margin: 8px;
cursor: pointer;
}
.panel .fa {
opacity: 1;
}
.panel:hover .panel-heading {
background-color: #ff8300;
}
.panel:hover {
box-shadow: 2px 2px 3px 3px rgba(102, 102, 102, 0.8);
}
.panel:hover .fa {
transition: all 0.2s ease, font-size 0.2s ease-in;
color: #ff8300;
text-shadow: 2px 2px 0px #FFFFFF;
}
.panel:hover .panel-heading .fa {
color: #333333;
}
.panel-heading .fa-exclamation-circle {
color: yellow;
}
.panel-heading .fa-check {
color: #FFF;
}
.panel-heading .fa-fire {
color: #ff8300;
font-size: 26px;
}
.panel-body b.fa {
width: 30px;
font-size: 20px;
text-align: center;
}
#configurationList {
width: 99%;
-webkit-flex-flow: row wrap;
display: flex;
flex-flow: row wrap;
justify-content: space-around;
}
#configurationList .panel {
display: inline-block;
width: 250px;
min-height: 100px;
}
@media screen and (max-width: 720px) {
#configurationList .panel {
width: 340px; /* up to 2 col */
}
}
@media screen and (max-width: 1024px) {
#configurationList .panel {
width: 200px; /* up to 5 col */
}
}
</style>
</head>
<body>
<div class='page-header page-header-fixed'>
<h1>Configuration</h1>
</div>
<div id='configurationList'>
<div class='tile'>
<h2>
<b class='fa fa-refresh fa-spin'></b>
<i>Loading, please wait...</i>
</h2>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment