More LSP updates from Carina.

This commit is contained in:
Thulinma 2015-02-14 00:03:38 +01:00
parent cc004dd5bb
commit 225a11132f
6 changed files with 461 additions and 128 deletions

View file

@ -179,7 +179,7 @@ MistOutJSON: src/output/mist_out.cpp src/output/output.cpp src/output/output_htt
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@ $(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
lspSOURCES=lsp/plugins/md5.js lsp/plugins/cattablesort.js lsp/mist.js lspSOURCES=lsp/plugins/md5.js lsp/plugins/cattablesort.js lsp/mist.js
lspSOURCESmin=lsp/plugins/jquery.js lsp/plugins/jquery.flot.min.js lsp/plugins/jquery.flot.time.min.js lspSOURCESmin=lsp/plugins/jquery.js lsp/plugins/jquery.flot.min.js lsp/plugins/jquery.flot.time.min.js lsp/plugins/jquery.qrcode.min.js
lspDATA=lsp/header.html lsp/main.css lsp/footer.html lspDATA=lsp/header.html lsp/main.css lsp/footer.html
JAVA := $(shell which java 2> /dev/null) JAVA := $(shell which java 2> /dev/null)

View file

@ -258,7 +258,6 @@ main > button {
} }
textarea { textarea {
font-size: 0.8em; font-size: 0.8em;
height: 20em;
} }
.unit { .unit {
color: #777; color: #777;
@ -401,13 +400,14 @@ table td.vheader {
padding: 0.8em 0.2em; padding: 0.8em 0.2em;
border-right: 1px solid #ccc; border-right: 1px solid #ccc;
background-image: linear-gradient(to left, #ddd, #eee); background-image: linear-gradient(to left, #ddd, #eee);
width: 1.5em;
} }
table td.vheader span { table td.vheader span {
transform: translate( calc(-50% + 0.75em) ) rotate(-90deg); transform: translate( calc(-50% + 0.75em) ) rotate(-90deg);
transform-origin: 50% 50%; transform-origin: 50% 50%;
white-space: nowrap; white-space: nowrap;
display: block; display: block;
width: 1.5em; position: absolute;
} }
table td, table th, .flextable .td, .flextable .th { table td, table th, .flextable .td, .flextable .th {
padding: 0.2em 0.8em; padding: 0.2em 0.8em;
@ -589,6 +589,11 @@ input[type=radio] {
border: 1px solid #ccc; border: 1px solid #ccc;
padding: 0.5em 1em; padding: 0.5em 1em;
} }
.legend > .close {
position: absolute;
top: 0.5em;
right: 0.5em;
}
.legend-list > label { .legend-list > label {
display: block; display: block;
} }
@ -599,6 +604,10 @@ input[type=radio] {
margin: 0 0.5em; margin: 0 0.5em;
box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.2); box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.2);
} }
.legend-list .close {
position: absolute;
right: 0.5em;
}
#tooltip { #tooltip {
position: absolute; position: absolute;
display: none; display: none;
@ -639,7 +648,36 @@ body:not(.helpme) .input_container .description {
body:not(.helpme) .input_container .ih_balloon { body:not(.helpme) .input_container .ih_balloon {
display: none; display: none;
} }
#popup {
position: fixed;
top: 5%;
left: 5%;
bottom: 5%;
right: 5%;
border: 1px solid #b4b4b4;
background-color: #fff;
box-shadow: 0.2em 0.2em 0.5em rgba(0,0,0,0.2);
padding: 0.5em;
z-index: 10;
color: rgba(0,0,0,0.9);
}
#popup > .close {
position: absolute;
top: 0.5em;
right: 0.5em;
}
.qr_container {
display: flex;
flex-flow: column nowrap;
width: 100%;
height: 100%;
text-align: center;
padding: 1em;
box-sizing: border-box;
}
.qr_container .qrcode {
flex-grow: 1;
}
@font-face { @font-face {
font-family: FuturaICGLight; font-family: FuturaICGLight;

View file

@ -58,7 +58,26 @@ var UI = {
helpme: true helpme: true
} }
}, },
interval: false, interval: {
clear: function(){
if (typeof this.opts == 'undefined') {
return;
}
clearInterval(this.opts.id);
delete this.opts;
},
set: function(callback,delay){
if (this.opts) {
log('[interval]','Set called on interval, but an interval is already active.');
}
this.opts = {
delay: delay,
callback: callback
};
this.opts.id = setInterval(callback,delay);
}
},
returnTab: ['Overview'], returnTab: ['Overview'],
countrylist: {'AF':'Afghanistan','AX':'Åland Islands','AL':'Albania','DZ':'Algeria','AS':'American Samoa','AD':'Andorra', countrylist: {'AF':'Afghanistan','AX':'Åland Islands','AL':'Albania','DZ':'Algeria','AS':'American Samoa','AD':'Andorra',
'AO':'Angola','AI':'Anguilla','AQ':'Antarctica','AG':'Antigua and Barbuda','AR':'Argentina','AM':'Armenia','AW':'Aruba', 'AO':'Angola','AI':'Anguilla','AQ':'Antarctica','AG':'Antigua and Barbuda','AR':'Argentina','AM':'Armenia','AW':'Aruba',
@ -131,6 +150,20 @@ var UI = {
}, },
element: $('<div>').attr('id','tooltip') element: $('<div>').attr('id','tooltip')
}, },
popup: {
element: null,
show: function(content) {
this.element = $('<div>').attr('id','popup').append(
$('<button>').text('Close').addClass('close').click(function(){
UI.popup.element.fadeOut('fast',function(){
UI.popup.element.remove();
UI.popup.element = null;
});
})
).append(content);
$('body').append(this.element);
}
},
menu: [ menu: [
{ {
Overview: {}, Overview: {},
@ -429,7 +462,7 @@ var UI = {
$field = $('<div>').addClass('radioselect'); $field = $('<div>').addClass('radioselect');
for (var i in e.radioselect) { for (var i in e.radioselect) {
var $radio = $('<input>').attr('type','radio').val(e.radioselect[i][0]).attr('name',e.label); var $radio = $('<input>').attr('type','radio').val(e.radioselect[i][0]).attr('name',e.label);
if (('LTSonly' in e) && (!mist.data.LTS)) { if ((('LTSonly' in e) && (!mist.data.LTS)) || (e.readonly)) {
$radio.prop('disabled',true); $radio.prop('disabled',true);
} }
var $label = $('<label>').append( var $label = $('<label>').append(
@ -443,7 +476,7 @@ var UI = {
$(this).parent().find('input[type=radio]:enabled').prop('checked','true'); $(this).parent().find('input[type=radio]:enabled').prop('checked','true');
}); });
$label.append($select); $label.append($select);
if (('LTSonly' in e) && (!mist.data.LTS)) { if ((('LTSonly' in e) && (!mist.data.LTS)) || (e.readonly)) {
$select.prop('disabled',true); $select.prop('disabled',true);
} }
for (var j in e.radioselect[i][2]) { for (var j in e.radioselect[i][2]) {
@ -486,6 +519,25 @@ var UI = {
$(this).select(); $(this).select();
}); });
} }
if ('qrcode' in e) {
$fc.append(
$('<span>').addClass('unit').html(
$('<button>').text('QR').click(function(){
var text = String($(this).closest('.field_container').find('.field').getval());
var $qr = $('<div>').addClass('qrcode');
UI.popup.show(
$('<span>').addClass('qr_container').append(
$('<p>').text(text)
).append($qr)
);
$qr.qrcode({
text: text,
size: Math.min($qr.width(),$qr.height())
})
})
)
);
}
if ('rows' in e) { if ('rows' in e) {
$field.attr('rows',e.rows); $field.attr('rows',e.rows);
} }
@ -792,8 +844,10 @@ var UI = {
var f = $(this).data('validate'); var f = $(this).data('validate');
f($(this)); f($(this));
}); });
if ($field.getval() != '') {
$field.trigger('change'); $field.trigger('change');
} }
}
if ('function' in e) { if ('function' in e) {
$field.on('change keyup',e['function']); $field.on('change keyup',e['function']);
@ -1014,7 +1068,28 @@ var UI = {
return $c.children(); return $c.children();
}, },
plot: { plot: {
addGraph: function(saveas,$graph_c){
var graph = {
id: saveas.id,
xaxis: saveas.xaxis,
datasets: [],
elements: {
cont: $('<div>').addClass('graph'),
plot: $('<div>').addClass('plot'),
legend: $('<div>').addClass('legend')
}
}
graph.elements.cont.append(
graph.elements.plot
).append(
graph.elements.legend
);
$graph_c.append(graph.elements.cont);
return graph;
},
go: function(graphs) { go: function(graphs) {
if (Object.keys(graphs).length < 1) { return; }
//get plotdata //get plotdata
//build request object //build request object
var reqobj = { var reqobj = {
@ -1093,10 +1168,25 @@ var UI = {
var $list = $('<div>').addClass('legend-list').addClass('checklist'); var $list = $('<div>').addClass('legend-list').addClass('checklist');
graph.elements.legend.html( graph.elements.legend.html(
$('<h3>').text(graph.id) $('<h3>').text(graph.id)
).append(
$('<button>').data('opts',graph).text('X').addClass('close').click(function(){
var graph = $(this).data('opts');
if (confirm('Are you sure you want to remove '+graph.id+'?')) {
graph.elements.cont.remove();
var $opt = $('.graph_ids option:contains('+graph.id+')');
var $select = $opt.parent();
$opt.remove();
UI.plot.del(graph.id);
delete graphs[graph.id];
$select.trigger('change');
UI.plot.go(graphs);
}
})
).append($list); ).append($list);
var plotdata = graph.plot.getOptions(); var plotdata = graph.plot.getOptions();
for (var i in graph.datasets) { for (var i in graph.datasets) {
var $checkbox = $('<input>').attr('type','checkbox').data('index',i).click(function(){ var $checkbox = $('<input>').attr('type','checkbox').data('index',i).data('graph',graph).click(function(){
var graph = $(this).data('graph');
if ($(this).is(':checked')) { if ($(this).is(':checked')) {
graph.datasets[$(this).data('index')].display = true; graph.datasets[$(this).data('index')].display = true;
} }
@ -1117,6 +1207,32 @@ var UI = {
$('<div>').addClass('series-color').css('background-color',graph.datasets[i].color) $('<div>').addClass('series-color').css('background-color',graph.datasets[i].color)
).append( ).append(
graph.datasets[i].label graph.datasets[i].label
).append(
$('<button>').text('X').addClass('close').data('index',i).data('graph',graph).click(function(){
var i = $(this).data('index');
var graph = $(this).data('graph');
if (confirm('Are you sure you want to remove '+graph.datasets[i].label+' from '+graph.id+'?')) {
graph.datasets.splice(i,1);
if (graph.datasets.length == 0) {
graph.elements.cont.remove();
var $opt = $('.graph_ids option:contains('+graph.id+')');
var $select = $opt.parent();
$opt.remove();
$select.trigger('change');
UI.plot.del(graph.id);
delete graphs[graph.id];
UI.plot.go(graphs);
}
else {
UI.plot.save(graph);
var obj = {};
obj[graph.id] = graph;
UI.plot.go(obj);
}
}
})
) )
); );
} }
@ -1159,6 +1275,29 @@ var UI = {
} }
},reqobj) },reqobj)
}, },
save: function(opts){
var graph = {
id: opts.id,
xaxis: opts.xaxis,
datasets: []
};
for (var i in opts.datasets) {
graph.datasets.push({
origin: opts.datasets[i].origin,
datatype: opts.datasets[i].datatype
});
}
var graphs = mist.stored.get().graphs || {};
graphs[graph.id] = graph;
mist.stored.set('graphs',graphs);
},
del: function(graphid){
var graphs = mist.stored.get().graphs || {};
delete graphs[graphid];
mist.stored.set('graphs',graphs);
},
datatype: { datatype: {
getOptions: function (opts) { getOptions: function (opts) {
var general = $.extend(true,{},UI.plot.datatype.templates.general); var general = $.extend(true,{},UI.plot.datatype.templates.general);
@ -1185,7 +1324,7 @@ var UI = {
//slightly randomize the color //slightly randomize the color
var color = []; var color = [];
var variation = 75; var variation = 50;
for (var i in opts.basecolor) { for (var i in opts.basecolor) {
var c = opts.basecolor[i]; var c = opts.basecolor[i];
c += variation * (0.5 - Math.random()); c += variation * (0.5 - Math.random());
@ -1514,20 +1653,38 @@ var UI = {
} }
}, },
navto: function(tab,other){ navto: function(tab,other){
var hash = location.hash.split('@'); var prevhash = location.hash;
var hash = prevhash.split('@');
hash[0] = [mist.user.name,mist.user.host].join('&'); hash[0] = [mist.user.name,mist.user.host].join('&');
hash[1] = [tab,other].join('&'); hash[1] = [tab,other].join('&');
location.hash = hash.join('@'); location.hash = hash.join('@');
if (location.hash == prevhash) {
//manually trigger hashchange even though hash hasn't changed
$(window).trigger('hashchange'); $(window).trigger('hashchange');
clearInterval(UI.interval); }
}, },
showTab: function(tab,other) { showTab: function(tab,other) {
UI.elements.menu.css('visibility','visible').find('.button').removeClass('active').filter(function(){
if ($(this).find('.plain').text() == tab) { return true; }
}).addClass('active');
UI.elements.secondary_menu.html('');
var $main = UI.elements.main; var $main = UI.elements.main;
clearInterval(UI.interval);
if ((mist.user.loggedin) && (!('ui_settings' in mist.data))) {
$main.html('Loading..');
mist.send(function(){
UI.showTab(tab,other);
},{ui_settings: true});
return;
}
var $currbut = UI.elements.menu.css('visibility','visible').find('.button').filter(function(){
if ($(this).find('.plain').text() == tab) { return true; }
});
if ($currbut.length > 0) {
//only remove previous button highlight if the current tab is found in the menu
UI.elements.menu.find('.button.active').removeClass('active');
$currbut.addClass('active');
}
UI.elements.secondary_menu.html('');
UI.interval.clear();
$main.html( $main.html(
$('<h2>').text(tab) $('<h2>').text(tab)
); );
@ -1793,15 +1950,16 @@ var UI = {
])); ]));
if (mist.data.LTS) { if (mist.data.LTS) {
function update_update() { function update_update() {
if (!('uptodate' in mist.data.update)) { var info = mist.stored.get().update || {};
if (!('uptodate' in info)) {
$versioncheck.text('Unknown'); $versioncheck.text('Unknown');
return; return;
} }
else if (mist.data.update.error) { else if (info.error) {
$versioncheck.addClass('red').text(mist.data.update.error); $versioncheck.addClass('red').text(info.error);
return; return;
} }
else if (mist.data.update.uptodate) { else if (info.uptodate) {
$versioncheck.text('Your version is up to date.').addClass('green'); $versioncheck.text('Your version is up to date.').addClass('green');
return; return;
} }
@ -1816,10 +1974,11 @@ var UI = {
} }
} }
if ((!mist.data.update) || (!mist.data.update.lastchecked) || ((new Date()).getTime()-mist.data.update.lastchecked > 3600e3)) { if ((!mist.stored.get().update) || ((new Date()).getTime()-mist.stored.get().update.lastchecked > 24*3600e3)) {
if (!('update' in mist.data)) { mist.data.update = {}; } var update = mist.stored.get().update || {};
mist.data.update.lastchecked = (new Date()).getTime(); update.lastchecked = (new Date()).getTime();
mist.send(function(d){ mist.send(function(d){
mist.stored.set('update',$.extend(true,update,d.update));
update_update(); update_update();
},{checkupdate: true}); },{checkupdate: true});
} }
@ -1848,7 +2007,7 @@ var UI = {
else { else {
var active = '?'; var active = '?';
} }
$streamsonline.text(active+' active, '+Object.keys(mist.data.streams).length+' configured'); $streamsonline.text(active+' active, '+(mist.data.streams ? Object.keys(mist.data.streams).length : 0)+' configured');
if (('totals' in mist.data) && ('all_streams' in mist.data.totals)) { if (('totals' in mist.data) && ('all_streams' in mist.data.totals)) {
var clients = mist.data.totals.all_streams.all_protocols.clients; var clients = mist.data.totals.all_streams.all_protocols.clients;
clients = (clients.length ? UI.format.number(clients[clients.length-1][1]) : 0); clients = (clients.length ? UI.format.number(clients[clients.length-1][1]) : 0);
@ -1861,7 +2020,7 @@ var UI = {
} }
updateViewers(); updateViewers();
enterStats(); enterStats();
UI.interval = setInterval(updateViewers,30e3); UI.interval.set(updateViewers,30e3);
break; break;
case 'Protocols': case 'Protocols':
@ -1953,7 +2112,7 @@ var UI = {
} }
} }
updateProtocols(); updateProtocols();
UI.interval = setInterval(function(){ UI.interval.set(function(){
mist.send(function(){ mist.send(function(){
updateProtocols(); updateProtocols();
}); });
@ -1993,6 +2152,9 @@ var UI = {
mist.data.config.protocols[other] = saveas; mist.data.config.protocols[other] = saveas;
} }
else { else {
if (!mist.data.config.protocols) {
mist.data.config.protocols = [];
}
mist.data.config.protocols.push(saveas); mist.data.config.protocols.push(saveas);
} }
mist.send(function(d){ mist.send(function(d){
@ -2177,7 +2339,7 @@ var UI = {
$('<tr>').data('index',streamname).html( $('<tr>').data('index',streamname).html(
$('<td>').html(streamnamelabel).attr('title',streamname).addClass('overflow_ellipsis') $('<td>').html(streamnamelabel).attr('title',streamname).addClass('overflow_ellipsis')
).append( ).append(
$('<td>').text(stream.source).addClass('description') $('<td>').text(stream.source).attr('title',stream.source).addClass('description').addClass('overflow_ellipsis').css('max-width','20em')
).append( ).append(
$('<td>').data('sort-value',stream.online).html(UI.format.status(stream)) $('<td>').data('sort-value',stream.online).html(UI.format.status(stream))
).append( ).append(
@ -2231,13 +2393,16 @@ var UI = {
for (var s in mist.data.streams) { for (var s in mist.data.streams) {
if (mist.inputMatch(mist.data.capabilities.inputs.Folder.source_match,mist.data.streams[s].source)) { if (mist.inputMatch(mist.data.capabilities.inputs.Folder.source_match,mist.data.streams[s].source)) {
//this is a folder stream //this is a folder stream
mist.send(function(){ allstreams[s].source += '*';
mist.send(function(d,opts){
var s = opts.stream;
for (var i in mist.data.browse.files) { for (var i in mist.data.browse.files) {
for (var j in mist.data.capabilities.inputs) { for (var j in mist.data.capabilities.inputs) {
if ((j == 'Buffer') || (j == 'Folder')) { continue; } if ((j == 'Buffer') || (j == 'Folder')) { continue; }
if (mist.inputMatch(mist.data.capabilities.inputs[j].source_match,'/'+mist.data.browse.files[i])) { if (mist.inputMatch(mist.data.capabilities.inputs[j].source_match,'/'+mist.data.browse.files[i])) {
var streamname = s+'+'+mist.data.browse.files[i]; var streamname = s+'+'+mist.data.browse.files[i];
allstreams[streamname] = createWcStreamObject(streamname,mist.data.streams[s]); allstreams[streamname] = createWcStreamObject(streamname,mist.data.streams[s]);
allstreams[streamname].source = mist.data.streams[s].source+mist.data.browse.files[i];
} }
} }
} }
@ -2247,11 +2412,11 @@ var UI = {
updateStreams(); updateStreams();
},{active_streams: true}); },{active_streams: true});
UI.interval = setInterval(function(){ UI.interval.set(function(){
updateStreams(); updateStreams();
},30e3); },30e3);
} }
},{browse:mist.data.streams[s].source}); },{browse:mist.data.streams[s].source},{stream: s});
browserequests++; browserequests++;
} }
} }
@ -2260,7 +2425,7 @@ var UI = {
updateStreams(); updateStreams();
},{active_streams: true}); },{active_streams: true});
UI.interval = setInterval(function(){ UI.interval.set(function(){
updateStreams(); updateStreams();
},30e3); },30e3);
} }
@ -2270,7 +2435,7 @@ var UI = {
updateStreams(); updateStreams();
},{active_streams: true}); },{active_streams: true});
UI.interval = setInterval(function(){ UI.interval.set(function(){
updateStreams(); updateStreams();
},30e3); },30e3);
} }
@ -2407,6 +2572,10 @@ var UI = {
type: 'save', type: 'save',
label: 'Save', label: 'Save',
'function': function(){ 'function': function(){
if (!mist.data.streams) {
mist.data.streams = {};
}
mist.data.streams[saveas.name] = saveas; mist.data.streams[saveas.name] = saveas;
if (other != saveas.name) { if (other != saveas.name) {
delete mist.data.streams[other]; delete mist.data.streams[other];
@ -2580,6 +2749,20 @@ var UI = {
return retobj; return retobj;
} }
var embedbase = 'http://'+parseURL(mist.user.host).host+http_port+'/'; var embedbase = 'http://'+parseURL(mist.user.host).host+http_port+'/';
var embedoptions = {};
function embedhtml(opts) {
var open = ['div'];
var inner = "\n"+' <script src="'+embedbase+'embed_'+other+'.js"><'+'/script>'+"\n"; //don't leave the closing script tag complete
if (opts.autoplay) {
open.push('data-autoplay');
}
if ((opts.forceprotocol) && (opts.forceprotocol != '')) {
open.push('data-forcetype="'+opts.forceprotocol+'"');
}
return '<'+open.join(' ')+'>'+inner+'</div>';
}
var $protocolurls = $('<span>');
$embedlinks.append( $embedlinks.append(
$('<h3>').text('Embed urls') $('<h3>').text('Embed urls')
).append(UI.buildUI([ ).append(UI.buildUI([
@ -2587,21 +2770,49 @@ var UI = {
label: 'Embed url', label: 'Embed url',
type: 'str', type: 'str',
value: embedbase+'embed_'+other+'.js', value: embedbase+'embed_'+other+'.js',
readonly: true readonly: true,
},{ qrcode: true
label: 'Embed code',
type: 'textarea',
value: '<div>'+"\n"+' <"+"script src="'+embedbase+'embed_'+other+'.js"><"+"/script>'+"\n"+'</div>',
rows: 4,
readonly: true
},{ },{
label: 'Info url', label: 'Info url',
type: 'str', type: 'str',
value: embedbase+'info_'+other+'.js', value: embedbase+'info_'+other+'.js',
qrcode: true,
readonly: true readonly: true
},$('<h3>').text('Embed code'),{
label: 'Embed code',
type: 'textarea',
value: embedhtml(embedoptions),
rows: 4,
readonly: true,
classes: ['embed_code']
},$('<h4>').text('Embed code options').css('margin-top',0),{
label: 'Autoplay',
type: 'checkbox',
pointer: {
main: embedoptions,
index: 'autoplay'
},
'function': function(){
embedoptions.autoplay = $(this).getval();
$('.embed_code').setval(embedhtml(embedoptions));
} }
},{
label: 'Force protocol',
type: 'select',
select: [['','Automatic']],
pointer: {
main: embedoptions,
index: 'protocol'
},
classes: ['embed_code_forceprotocol'],
'function': function(){
embedoptions.forceprotocol = $(this).getval();
$('.embed_code').setval(embedhtml(embedoptions));
}
},$('<h3>').text('Protocol stream urls'),$protocolurls
])); ]));
var $trackinfo = $('<span>').append( var $trackinfo = $('<span>').append(
$('<h3>').text('Meta information') $('<h3>').text('Meta information')
).hide(); ).hide();
@ -2714,7 +2925,7 @@ var UI = {
var $protocols = $('<div>').css('float','left'); var $protocols = $('<div>').css('float','left');
$preview.append($video).append($protocols); $preview.append($video).append($protocols);
if (UI.stored.vars.autoplay) { if (mist.stored.get().autoplay) {
$video.attr('data-autoplay',''); $video.attr('data-autoplay','');
} }
@ -2726,26 +2937,37 @@ var UI = {
var script = document.createElement('script'); var script = document.createElement('script');
script.src = embedbase+'embed_'+other+'.js'; script.src = embedbase+'embed_'+other+'.js';
script.onerror = function(){ script.onerror = function(){
$video.text('Error loading "'+script.src+'".'); $video.html('Error loading "'+script.src+'".<br>').append(
$('<button>').text('Try again').click(function(){
loadVideo();
})
);
$protocols.text('');
}; };
script.onload = function(){ script.onload = function(){
if (typeof mistvideo[other].error != 'undefined') { if (typeof mistvideo[other].error != 'undefined') {
$video.text(mistvideo[other].error); $video.html(mistvideo[other].error+'"<br>').append(
$('<button>').text('Try again').click(function(){
loadVideo();
})
);
$protocols.text('');
return; return;
} }
var vid = mistvideo[other]; var vid = mistvideo[other];
var $url = UI.buildUI([{ var $url = UI.buildUI([{
label: 'Stream embed url', label: 'Protocol stream url',
type: 'str', type: 'str',
readonly: true, readonly: true,
value: (vid.embedded ? vid.embedded.url : '') value: (vid.embedded ? vid.embedded.url : ''),
qrcode: true
},{ },{
label: 'Autoplay (from now on)', label: 'Autoplay (from now on)',
type: 'checkbox', type: 'checkbox',
value: UI.stored.vars.autoplay, value: mist.stored.get().autoplay,
'function': function(){ 'function': function(){
UI.stored.saveOpt('autoplay',$(this).getval()); mist.stored.set('autoplay',($(this).getval() ? 1 : 0));
} }
}]); }]);
$url.find('.help_container').remove(); $url.find('.help_container').remove();
@ -2771,48 +2993,72 @@ var UI = {
$protocols.html($table); $protocols.html($table);
var $tbody = $('<tbody>'); var $tbody = $('<tbody>');
$table.append($tbody); $table.append($tbody);
var $protoselect = $('.embed_code_forceprotocol');
var buildurls = [];
$protoselect.find('.clear').remove();
for (var i in vid.source) { for (var i in vid.source) {
var source = vid.source[i]; var source = vid.source[i];
var type = source.type.split('/'); var type = source.type.split('/');
var humantype = type[0]; var humantype = type[0];
if (humantype.length < 6) {
humantype = humantype.toUpperCase();
}
switch (type.length) { switch (type.length) {
case 1: case 1:
break; break;
case 2: case 2:
humantype += ' v'+type[1]; humantype = UI.format.capital(type[0])+' v'+type[1];
if (type[0] == 'flash') { if (type[0] == 'flash') {
switch (type[1]) { switch (type[1]) {
case '7': case '7':
humantype = 'Progressive ('+humantype.charAt(0).toUpperCase()+humantype.slice(1)+')'; humantype = 'Progressive ('+humantype+')';
break; break;
case '10': case '10':
humantype = 'RTMP ('+humantype.charAt(0).toUpperCase()+humantype.slice(1)+')'; humantype = 'RTMP ('+humantype+')';
break; break;
case '11': case '11':
humantype = 'HDS ('+humantype.charAt(0).toUpperCase()+humantype.slice(1)+')'; humantype = 'HDS ('+humantype+')';
break; break;
} }
} }
break; break;
case 3: case 3:
switch (type[2]) { switch (type[2]) {
case 'mp4':
humantype += ' MP4';
break;
case 'vnd.apple.mpegurl': case 'vnd.apple.mpegurl':
humantype += ' HLS'; humantype += ' HLS';
break; break;
case 'vnd.ms-ss': case 'vnd.ms-ss':
humantype += ' Smooth'; humantype += ' Smooth';
break; break;
case 'mp2t':
humantype += ' TS';
break;
default: default:
humantype = source.type; if (type[2].length < 6) {
type[2] = type[2].toUpperCase();
}
humantype += ' '+type[2];
if (type[1] != 'video') {
humantype += ' ('+type[1]+')';
}
} }
break; break;
default: default:
humantype = source.type; humantype = source.type;
} }
humantype = UI.format.capital(humantype); humantype = UI.format.capital(humantype);
$protoselect.append(
$('<option>').text(humantype).val(source.type).addClass('clear')
);
buildurls.push({
label: humantype,
type: 'str',
value: source.url,
readonly: true,
qrcode: true
});
var $tr = $('<tr>'); var $tr = $('<tr>');
$tbody.append($tr); $tbody.append($tr);
$tr.html( $tr.html(
@ -2836,6 +3082,9 @@ var UI = {
$tr.find('input[type=radio]').prop('checked',true); $tr.find('input[type=radio]').prop('checked',true);
} }
} }
$protocolurls.html(
UI.buildUI(buildurls)
);
}; };
$video.html('')[0].appendChild(script); $video.html('')[0].appendChild(script);
} }
@ -2908,10 +3157,7 @@ var UI = {
['server','The entire server'], ['server','The entire server'],
['stream','The stream:',thestreams] ['stream','The stream:',thestreams]
]; ];
if ((UI.returnTab[0] == 'Edit Stream') && (UI.returnTab[1])) { var appliesto = {
var value = ['stream',UI.returnTab[1]];
}
build.push({
label: 'Applies to', label: 'Applies to',
type: 'radioselect', type: 'radioselect',
radioselect: select, radioselect: select,
@ -2920,9 +3166,13 @@ var UI = {
index: 'applies_to' index: 'applies_to'
}, },
LTSonly: true, LTSonly: true,
validate: ['required'], validate: ['required']
value: value };
}); if ((UI.returnTab[0] == 'Edit Stream') && (UI.returnTab[1])) {
appliesto.value = ['stream',UI.returnTab[1]];
appliesto.readonly = true;
}
build.push(appliesto);
} }
else { else {
var pointer = other.split('^'); var pointer = other.split('^');
@ -3049,7 +3299,7 @@ var UI = {
delete saveas.applies_to; delete saveas.applies_to;
switch (pointer[0]) { switch (pointer[0]) {
case 'server': case 'server':
if (typeof mist.data.config.limits == 'undefined') { if (!mist.data.config.limits) {
mist.data.config.limits = []; mist.data.config.limits = [];
} }
mist.data.config.limits.push(saveas); mist.data.config.limits.push(saveas);
@ -3103,7 +3353,7 @@ var UI = {
value: 30, value: 30,
'function': function(){ 'function': function(){
clearInterval(UI.interval); clearInterval(UI.interval);
UI.interval = setInterval(function(){ UI.interval.set(function(){
mist.send(function(){ mist.send(function(){
buildLogsTable(); buildLogsTable();
}); });
@ -3166,7 +3416,7 @@ var UI = {
$main.append($UI); $main.append($UI);
var saveas = {}; var saveas = {};
var graphs = {}; var graphs = (mist.stored.get().graphs ? $.extend(true,{},mist.stored.get().graphs) : {});
var thestreams = {}; var thestreams = {};
//let's not bother with folder streams, if they aren't active anyway //let's not bother with folder streams, if they aren't active anyway
@ -3205,18 +3455,38 @@ var UI = {
'function': function(){ 'function': function(){
if (! $(this).val()) { return; } if (! $(this).val()) { return; }
var $s = $UI.find('.graph_xaxis'); var $s = $UI.find('.graph_xaxis');
var $id = $UI.find('.graph_id');
if ($(this).val() == 'new') { if ($(this).val() == 'new') {
$s.children('option').prop('disabled',false); $s.children('option').prop('disabled',false);
$id.setval('Graph '+(Object.keys(graphs).length +1)).closest('label').show();
} }
else { else {
var xaxistype = graphs[$(this).val()].xaxis; var xaxistype = graphs[$(this).val()].xaxis;
$s.children('option').prop('disabled',true).filter('[value="'+xaxistype+'"]').prop('disabled',false); $s.children('option').prop('disabled',true).filter('[value="'+xaxistype+'"]').prop('disabled',false);
$id.closest('label').hide();
} }
if ($s.children('option[value="'+$s.val()+'"]:disabled').length) { if ($s.children('option[value="'+$s.val()+'"]:disabled').length) {
$s.val($s.children('option:enabled').first().val()); $s.val($s.children('option:enabled').first().val());
}
$s.trigger('change'); $s.trigger('change');
} }
},{
label: 'Graph id',
type: 'str',
pointer: {
main: saveas,
index: 'id'
},
classes: ['graph_id'],
validate: [function(val,me){
if (val in graphs) {
return {
msg:'This graph id has already been used. Please enter something else.',
classes: ['red']
} }
}
return false;
}]
},{ },{
label: 'Axis type', label: 'Axis type',
type: 'select', type: 'select',
@ -3239,7 +3509,7 @@ var UI = {
$s.children('option').prop('disabled',false).filter('[value="coords"]').prop('disabled',true); $s.children('option').prop('disabled',false).filter('[value="coords"]').prop('disabled',true);
break; break;
} }
if ($s.children('option[value="'+$s.val()+'"]:disabled').length) { if ((!$s.val()) || ($s.children('option[value="'+$s.val()+'"]:disabled').length)) {
$s.val($s.children('option:enabled').first().val()); $s.val($s.children('option:enabled').first().val());
$s.trigger('change'); $s.trigger('change');
} }
@ -3294,24 +3564,10 @@ var UI = {
type: 'save', type: 'save',
'function': function(){ 'function': function(){
//the graph options //the graph options
var graph;
if (saveas.graph == 'new') { if (saveas.graph == 'new') {
var graph = { graph = UI.plot.addGraph(saveas,$graph_c);
id: 'Graph '+(Object.keys(graphs).length+1),
xaxis: saveas.xaxis,
datasets: [],
elements: {
cont: $('<div>').addClass('graph'),
plot: $('<div>').addClass('plot'),
legend: $('<div>').addClass('legend')
}
}
graphs[graph.id] = graph; graphs[graph.id] = graph;
graph.elements.cont.append(
graph.elements.plot
).append(
graph.elements.legend
);
$graph_c.append(graph.elements.cont);
$UI.find('select.graph_ids').append( $UI.find('select.graph_ids').append(
$('<option>').text(graph.id) $('<option>').text(graph.id)
).val(graph.id).trigger('change'); ).val(graph.id).trigger('change');
@ -3325,21 +3581,43 @@ var UI = {
origin: saveas.origin origin: saveas.origin
}); });
graph.datasets.push(opts); graph.datasets.push(opts);
UI.plot.save(graph);
UI.plot.go(graphs); UI.plot.go(graphs);
} }
}] }]
}])); }]));
$UI.find('.graph_xaxis').trigger('change');
var $graph_c = $('<div>').addClass('graph_container'); var $graph_c = $('<div>').addClass('graph_container');
$main.append($graph_c); $main.append($graph_c);
},{active_streams: true, capabilities: true}); var $graph_ids = $UI.find('select.graph_ids');
for (var i in graphs) {
var graph = UI.plot.addGraph(graphs[i],$graph_c);
$graph_ids.append(
$('<option>').text(graph.id)
).val(graph.id);
UI.interval = setInterval(function(){ //the dataset options
var datasets = [];
for (var j in graphs[i].datasets) {
var opts = UI.plot.datatype.getOptions({
datatype: graphs[i].datasets[j].datatype,
origin: graphs[i].datasets[j].origin
});
datasets.push(opts);
}
graph.datasets = datasets;
graphs[graph.id] = graph;
}
$graph_ids.trigger('change');
UI.plot.go(graphs);
UI.interval.set(function(){
UI.plot.go(graphs); UI.plot.go(graphs);
},10e3); },10e3);
},{active_streams: true, capabilities: true});
break; break;
case 'Server Stats': case 'Server Stats':
if (typeof mist.data.capabilities == 'undefined') { if (typeof mist.data.capabilities == 'undefined') {
@ -3411,21 +3689,13 @@ var UI = {
vheader: 'Load average', vheader: 'Load average',
labels: ['1 minute','5 minutes','15 minutes',''], labels: ['1 minute','5 minutes','15 minutes',''],
content: [{ content: [{
header: 'Absolute', header: '&nbsp;',
body: [ body: [
UI.format.number(load.one/100), UI.format.number(load.one/100),
UI.format.number(load.five/100), UI.format.number(load.five/100),
UI.format.number(load.fifteen/100), UI.format.number(load.fifteen/100),
'' ''
] ]
},{
header: 'Per core',
body: [
UI.format.addUnit(load.one/cores,'%'),
UI.format.addUnit(load.five/cores,'%'),
UI.format.addUnit(load.fifteen/cores,'%'),
''
]
}] }]
}; };
var nload = UI.buildVheaderTable(loading); var nload = UI.buildVheaderTable(loading);
@ -3453,7 +3723,7 @@ var UI = {
) )
); );
UI.interval = setInterval(function(){ UI.interval.set(function(){
mist.send(function(){ mist.send(function(){
buildstattables(); buildstattables();
},{capabilities: true}); },{capabilities: true});
@ -3509,6 +3779,7 @@ var UI = {
} }
},{ },{
type: 'textarea', type: 'textarea',
rows: 20,
label: 'Your message', label: 'Your message',
validate: ['required'], validate: ['required'],
pointer: { pointer: {
@ -3517,6 +3788,7 @@ var UI = {
} }
},{ },{
type: 'textarea', type: 'textarea',
rows: 20,
label: 'Your config file', label: 'Your config file',
readonly: true, readonly: true,
value: config, value: config,
@ -3565,7 +3837,7 @@ var mist = {
user: { user: {
name: '', name: '',
password: '', password: '',
host: 'http://localhost:4242/api' host: 'http://'+(location.hostname ? location.hostname : 'localhost')+':4242/api'
}, },
send: function(callback,sendData,opts){ send: function(callback,sendData,opts){
sendData = sendData || {}; sendData = sendData || {};
@ -3592,6 +3864,7 @@ var mist = {
async: true, async: true,
error: function(jqXHR,textStatus,errorThrown){ error: function(jqXHR,textStatus,errorThrown){
//connection failed //connection failed
delete mist.user.loggedin;
if (!opts.hide) { if (!opts.hide) {
switch (textStatus) { switch (textStatus) {
@ -3618,7 +3891,8 @@ var mist = {
UI.navto('Login'); UI.navto('Login');
}, },
success: function(d){ success: function(d){
log('Received',$.extend(true,{},d)); log('Receive',$.extend(true,{},d));
delete mist.user.loggedin;
switch (d.authorize.status) { switch (d.authorize.status) {
case 'OK': case 'OK':
//communication succesfull //communication succesfull
@ -3747,7 +4021,7 @@ var mist = {
} }
} }
if (callback) { callback(d); } if (callback) { callback(d,opts); }
break; break;
case 'CHALL': case 'CHALL':
if (d.authorize.challenge == mist.user.authstring) { if (d.authorize.challenge == mist.user.authstring) {
@ -3862,6 +4136,24 @@ var mist = {
} }
} }
return build; return build;
},
stored: {
get: function(){
return mist.data.ui_settings || {};
},
set: function(name,val){
var settings = this.get();
settings[name] = val;
mist.send(function(){
},{ui_settings: settings});
},
del: function(name){
delete mist.data.ui_settings[name];
mist.send(function(){
},{ui_settings: mist.data.ui_settings});
}
} }
}; };

2
lsp/plugins/jquery.qrcode.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -11,6 +11,7 @@
<script src='plugins/cattablesort.js'></script> <script src='plugins/cattablesort.js'></script>
<script src='plugins/jquery.flot.min.js'></script> <script src='plugins/jquery.flot.min.js'></script>
<script src='plugins/jquery.flot.time.min.js'></script> <script src='plugins/jquery.flot.time.min.js'></script>
<script src='plugins/jquery.qrcode.min.js'></script>
<script src='mist.js'></script> <script src='mist.js'></script>
</head> </head>
<body> <body>

View file

@ -183,7 +183,7 @@ function mistembed(streamname) {
break; break;
default: default:
container.innerHTML += '<strong>Missing embed code for output type "'+src.type+'"</strong>'; container.innerHTML += '<strong>Missing embed code for output type "'+src.type+'"</strong>';
video.error = 'Missing embed code for output type "'+src.type;
} }
} }