+ added status to protocol tab
+ added ID to streams tab
+ added sorting to streams tab
* minor bugfixes
This commit is contained in:
cat 2012-12-28 10:51:15 +01:00 committed by Thulinma
parent f0ab171a8b
commit a90b3d5139
8 changed files with 935 additions and 692 deletions

View file

@ -1,18 +1,18 @@
/** /**
* Show a confirm dialog * Show a confirm dialog
* @param question the question displayed * @param question the question displayed
*/ */
function confirmDelete(question) function confirmDelete(question)
{ {
return confirm(question); return confirm(question);
} }
/** /**
* Format a date to mm/dd/yyyy hh:mm:ss format * Format a date to mm/dd/yyyy hh:mm:ss format
* @param date the date to format (timestamp) * @param date the date to format (timestamp)
*/ */
function formatDate(date) function formatDate(date)
{ {
var d = new Date(date * 1000); var d = new Date(date * 1000);
@ -29,10 +29,10 @@
} }
/** /**
* Find out what kind of resource an URI is * Find out what kind of resource an URI is
* @param uri the URI to check. If it start with a protocol (ebut not file://) return 'Live', else 'Recorded' * @param uri the URI to check. If it start with a protocol (ebut not file://) return 'Live', else 'Recorded'
*/ */
function TypeofResource(uri) function TypeofResource(uri)
{ {
var protocol = /([a-zA-Z]+):\/\//.exec(uri); var protocol = /([a-zA-Z]+):\/\//.exec(uri);
@ -46,10 +46,10 @@
} }
/** /**
* convert a short limit name to a long one using the table above * convert a short limit name to a long one using the table above
* @param name the short name of a limit * @param name the short name of a limit
*/ */
function shortToLongLimit(name) function shortToLongLimit(name)
{ {
var i; var i;
@ -66,13 +66,13 @@
} }
/** /**
* forse the server to save to the config file * forse the server to save to the config file
* @param callback function to call after the command is send * @param callback function to call after the command is send
*/ */
function forceJSONSave(callback) function forceJSONSave(callback)
{ {
// build the object to send to the server // build the object to send to the server
var data = var data =
{ {
'authorize': 'authorize':
@ -83,7 +83,7 @@
'save': 1 'save': 1
}; };
// make the XHR call // make the XHR call
$.ajax( $.ajax(
{ {
'url': settings.server, 'url': settings.server,
@ -99,11 +99,11 @@
} }
/** /**
* retrieves data from the server ;) * retrieves data from the server ;)
* note: does not authenticate first. Assumes user is logged in. * note: does not authenticate first. Assumes user is logged in.
* @param callback the function to call when the data has been retrieved. This callback has 1 parameter, the data retrieved. * @param callback the function to call when the data has been retrieved. This callback has 1 parameter, the data retrieved.
*/ */
function getData(callback) function getData(callback)
{ {
var data = var data =
@ -113,7 +113,7 @@
'username': settings.credentials.username, 'username': settings.credentials.username,
'password': (settings.credentials.authstring != "" ? MD5(MD5(settings.credentials.password) + settings.credentials.authstring) : "" ) 'password': (settings.credentials.authstring != "" ? MD5(MD5(settings.credentials.password) + settings.credentials.authstring) : "" )
}, },
'capabilities': {} 'capabilities': {}
}; };
$.ajax( $.ajax(
@ -132,11 +132,12 @@
var ret = $.extend(true, var ret = $.extend(true,
{ {
"streams": {}, "streams": {},
"capabilities": {}, "capabilities": {},
"statistics": {} "statistics": {}
}, d); }, d);
console.log('[651] RECV', ret); //IE breaks if the console isn't opened, so keep commented when committing
//console.log('[651] RECV', ret);
if(callback) if(callback)
{ {
@ -147,113 +148,113 @@
} }
/** /**
* retrieved the status and number of viewers from all streams * retrieved the status and number of viewers from all streams
* @param callback function that is called when the data is collected. Has one parameter, the data retrieved * @param callback function that is called when the data is collected. Has one parameter, the data retrieved
*/ */
function getStreamsData(callback) function getStreamsData(callback)
{ {
getData(function(data) getData(function(data)
{ {
var streams = {}; // streamID: [status, numViewers]; var streams = {}; // streamID: [status, numViewers];
var cnt = 0; var cnt = 0;
for(var stream in data.streams) for(var stream in data.streams)
{ {
streams[stream] = [data.streams[stream].online, 0]; streams[stream] = [data.streams[stream].online, 0];
cnt++; cnt++;
} }
if(cnt === 0) if(cnt === 0)
{ {
return; // if there are no streams, don't collect data and just return return; // if there are no streams, don't collect data and just return
} }
for(stream in data.statistics) for(stream in data.statistics)
{ {
if(data.statistics[stream].curr) if(data.statistics[stream].curr)
{ {
for(var viewer in data.statistics[stream].curr) for(var viewer in data.statistics[stream].curr)
{ {
streams[stream][1]++; streams[stream][1]++;
} }
} }
} }
callback(streams); callback(streams);
}); });
} }
/** /**
* parses an url and returns the parts of it. * parses an url and returns the parts of it.
* @return object containing the parts of the URL: protocol, host and port. * @return object containing the parts of the URL: protocol, host and port.
*/ */
function parseURL(url) function parseURL(url)
{ {
var pattern = /(https?)\:\/\/([^:\/]+)\:(\d+)?/i; var pattern = /(https?)\:\/\/([^:\/]+)\:(\d+)?/i;
var retobj = {protocol: '', host: '', port: ''}; var retobj = {protocol: '', host: '', port: ''};
var results = url.match(pattern); var results = url.match(pattern);
if(results != null) if(results != null)
{ {
retobj.protocol = results[1]; retobj.protocol = results[1];
retobj.host = results[2]; retobj.host = results[2];
retobj.port = results[3]; retobj.port = results[3];
} }
return retobj; return retobj;
} }
/** /**
* go figure. * go figure.
* @return true if there is a HTTP connector... and false if there isn't. * @return true if there is a HTTP connector... and false if there isn't.
*/ */
function isThereAHTTPConnector() function isThereAHTTPConnector()
{ {
var i, var i,
len = (settings.settings.config.protocols ? settings.settings.config.protocols.length : 0); len = (settings.settings.config.protocols ? settings.settings.config.protocols.length : 0);
for(i = 0; i < len; i++) for(i = 0; i < len; i++)
{ {
if(settings.settings.config.protocols[i].connector == 'HTTP') if(settings.settings.config.protocols[i].connector == 'HTTP')
{ {
return true; return true;
} }
} }
return false; return false;
} }
/** /**
* retrieve port of the http connector * retrieve port of the http connector
* @return the port number * @return the port number
*/ */
function getHTTPControllerPort() function getHTTPControllerPort()
{ {
var i, var i,
len = (settings.settings.config.protocols ? settings.settings.config.protocols.length : 0); len = (settings.settings.config.protocols ? settings.settings.config.protocols.length : 0);
for(i = 0; i < len; i++) for(i = 0; i < len; i++)
{ {
if(settings.settings.config.protocols[i].connector == 'HTTP') if(settings.settings.config.protocols[i].connector == 'HTTP')
{ {
return settings.settings.config.protocols[i].port; return settings.settings.config.protocols[i].port;
} }
} }
return 0; return 0;
} }
/** /**
* retrieves the stream status (online and total number of streams) and viewer info (total number of viewers). * retrieves the stream status (online and total number of streams) and viewer info (total number of viewers).
* @param callback function that is called when data is retrieved. Has one parameter, the retrieved data. * @param callback function that is called when data is retrieved. Has one parameter, the retrieved data.
*/ */
function getStatData(callback) function getStatData(callback)
{ {
getData(function(data) getData(function(data)
@ -290,14 +291,14 @@
} }
/** /**
* Connect to the server and retrieve the data * Connect to the server and retrieve the data
* @param callback the function to call when connected. Has one parameter, an optional error string. * @param callback the function to call when connected. Has one parameter, an optional error string.
*/ */
function loadSettings(callback) function loadSettings(callback)
{ {
// display 'loading, please wait' while retrieving data // display 'loading, please wait' while retrieving data
$('body').append( $('<div>').attr('id', 'shield').text('Loading, please wait...') ); $('body').append( $('<div>').attr('id', 'shield').text('Loading, please wait...') );
var errorstr = '', var errorstr = '',
data = $.extend(settings.settings, data = $.extend(settings.settings,
@ -311,8 +312,9 @@
delete data.log; // don't send the logs back to the server delete data.log; // don't send the logs back to the server
delete data.statistics; // same goes for the stats delete data.statistics; // same goes for the stats
console.log('[763] SEND', data); //IE breaks if the console isn't opened, so keep commented when committing
//console.log('[763] SEND', data);
$.ajax( $.ajax(
{ {
@ -328,13 +330,14 @@
'error': function() 'error': function()
{ {
showTab('disconnect'); showTab('disconnect');
$('#shield').remove(); // remove loading display $('#shield').remove(); // remove loading display
}, },
'success': function(d) 'success': function(d)
{ {
$('#shield').remove(); // remove loading display $('#shield').remove(); // remove loading display
console.log('[785] RECV', d); //IE breaks if the console isn't opened, so keep commented when committing
//console.log('[785] RECV', d);
if(d && d['authorize'] && d['authorize']['challenge']) if(d && d['authorize'] && d['authorize']['challenge'])
{ {
@ -358,7 +361,7 @@
"version": "" "version": ""
}, },
"streams": {}, "streams": {},
"capabilities": {}, "capabilities": {},
"log": {}, "log": {},
"statistics": {} "statistics": {}
}, d); }, d);
@ -372,10 +375,10 @@
} }
/** /**
* Sets the page's header text (loging in, connected, disconnected), title and pretty colors (!) * Sets the page's header text (loging in, connected, disconnected), title and pretty colors (!)
* @param state the state of the header. Possible are 'logingin', 'disconnected' or 'connected'. * @param state the state of the header. Possible are 'logingin', 'disconnected' or 'connected'.
*/ */
function setHeaderState(state) function setHeaderState(state)
{ {
var text, cname, title; var text, cname, title;
@ -396,22 +399,22 @@
/** /**
* Formats the status property to a string (with colors!) * Formats the status property to a string (with colors!)
* @param status, the status property of a stream * @param status, the status property of a stream
*/ */
function formatStatus(status) function formatStatus(status)
{ {
if(status == undefined) if(status == undefined)
{ {
return "<span>Unknown, checking...</span>"; return "<span>Unknown, checking...</span>";
} }
switch(status) switch(status)
{ {
case 1: return "<span class='green'>Running</span>"; break; case 1: return "<span class='green'>Running</span>"; break;
case 0: return "<span class='red'>Offline</span>"; break; case 0: return "<span class='red'>Offline</span>"; break;
default: return "<span class='green'>" + status + "</span>"; break; default: return "<span class='green'>" + status + "</span>"; break;
} }
} }

BIN
lsp/graphics/sort.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

BIN
lsp/graphics/sort_asc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

BIN
lsp/graphics/sort_desc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,7 @@
<script src='md5.js'></script> <script src='md5.js'></script>
<script src='main.js'></script> <script src='main.js'></script>
<script src='functions.js'></script> <script src='functions.js'></script>
<script src='tablesort.js'></script>
<link rel='stylesheet' href='style.css' /> <link rel='stylesheet' href='style.css' />

View file

@ -117,6 +117,7 @@ button
background-color: #505050; background-color: #505050;
color: #fff; color: #fff;
border: 0; border: 0;
margin: 0 2px 0 2px;
} }
@ -345,6 +346,20 @@ td
width: auto; width: auto;
padding: 0; padding: 0;
} }
.sortable th.sort-type-string, .sortable th.sort-type-int, .sortable th.sort-type-float
{
background: transparent url('graphics/sort.png') no-repeat 5px 50%;
}
.sortable th.sortasc
{
background-image: url('graphics/sort_asc.png');
}
.sortable th.sortdesc
{
background-image: url('graphics/sort_desc.png');
}
#protocoldesc p #protocoldesc p
{ {
font-weight: normal; font-weight: normal;
@ -352,7 +367,7 @@ td
} }
#protocolfields #protocolfields
{ {
margin-top: 10px; margin-top: 10px;
} }
#forcesave #forcesave

216
lsp/tablesort.js Normal file
View file

@ -0,0 +1,216 @@
// Stupid jQuery table plugin.
//http://joequery.github.com/Stupid-Table-Plugin/
// Call on a table
// sortFns: Sort functions for your datatypes.
(function($){
$.fn.stupidtable = function(sortFns){
var table = this; sortFns = sortFns || {};
// ==================================================== //
// Utility functions //
// ==================================================== //
// Merge sort functions with some default sort functions.
sortFns = $.extend({}, {
"int":function(a,b){ return parseInt(a, 10) - parseInt(b, 10); },
"float":function(a,b){ return parseFloat(a) - parseFloat(b); },
"string":function(a,b){ if (a<b) return -1; if (a>b) return +1; return 0;}
}, sortFns);
// Array comparison. See http://stackoverflow.com/a/8618383
var arrays_equal = function(a,b) { return !!a && !!b && !(a<b || b<a);}
// Return the resulting indexes of a sort so we can apply
// this result elsewhere. This returns an array of index numbers.
// return[0] = x means "arr's 0th element is now at x"
var sort_map = function(arr, sort_function){
var sorted = arr.slice(0).sort(sort_function);
var map = [];
var index = 0;
for(var i=0; i<arr.length; i++){
index = $.inArray(arr[i], sorted);
// If this index is already in the map, look for the next index.
// This handles the case of duplicate entries.
while($.inArray(index, map) != -1){
index++;
}
map.push(index);
}
return map;
}
// Apply a sort map to the array.
var apply_sort_map = function(arr, map){
var clone = arr.slice(0);
for(var i=0; i<map.length; i++){
newIndex = map[i];
clone[newIndex] = arr[i];
}
return clone;
}
// Returns true if array is sorted, false otherwise.
// Checks for both ascending and descending
var is_sorted_array = function(arr, sort_function){
var clone = arr.slice(0);
var reversed = arr.slice(0).reverse();
var sorted = arr.slice(0).sort(sort_function);
// Check if the array is sorted in either direction.
return arrays_equal(clone, sorted) || arrays_equal(reversed, sorted);
}
var what_order_sorted = function(data, sf, isa)
{
var tmp = [data[0], data[data.length - 1]];
tmp.sort(sf);
if(data[0] == tmp[0] || !isa)
{
return 'desc';
}else{
return 'asc';
}
}
// ==================================================== //
// Begin execution! //
// ==================================================== //
// Do sorting when THs are clicked
table.delegate("th", "click", function(){
if($(this).text().replace(/ /g, '') == '')
{
// empty header, don't allow sorting
return;
}
var trs = table.find("tbody tr");
var i = $(this).index();
var classes = $(this).attr("class");
var type = null;
if (classes){
classes = classes.split(/\s+/);
for(var j=0; j<classes.length; j++){
if(classes[j].search("sort-type-") != -1){
type = classes[j].replace('sort-', '');
break;
}
}
if(type){
type = type.split('-')[1];
}
else{
type = "string";
}
}
// Don't attempt to sort if no data type
//if(!type){return false;}
var sortMethod = sortFns[type];
// Gather the elements for this column
column = [];
// Push either the value of the 'data-order-by' attribute if specified
// or just the text() value in this column to column[] for comparison.
trs.each(function(index,tr){
var e = $(tr).children().eq(i);
var order_by = e.attr('data-order-by') || e.text();
column.push(order_by);
});
// If the column is already sorted, just reverse the order. The sort
// map is just reversing the indexes.
if(is_sorted_array(column, sortMethod)){
column.reverse();
var theMap = [];
for(var i=column.length-1; i>=0; i--){
theMap.push(i);
}
}else{
// Get a sort map and apply to all rows
theMap = sort_map(column, sortMethod);
}
// remove old sort classes (on this and other columns)
$(this).parent().find('th').each(function()
{
$(this).removeClass('sortasc sortdesc');
});
// what order are we sorting in?
var whatorder = what_order_sorted(column, sortMethod, is_sorted_array(column, sortMethod));
// set new sort class
$(this).addClass(whatorder == 'asc' ? 'sortasc' : 'sortdesc');
var sortedTRs = $(apply_sort_map(trs, theMap));
// Replace the content of tbody with the sortedTRs. Strangely (and
// conveniently!) enough, .append accomplishes this for us.
table.find("tbody").append(sortedTRs);
});
// remove th icon if no header text
$(this).find('th').each(function()
{
var hv = $(this).text().replace(/ /g, '');
if(hv == '')
{
$(this).css('background', 'transparent');
}
});
}
})(jQuery);
$('table.sortable').each(function()
{
var rows = $(this).find('tbody tr').length;
if(rows > 1)
{
$(this).stupidtable();
}else{
$(this).removeClass('sortable');
}
});