for readability and maintainability splitted lsp files
This commit is contained in:
		
							parent
							
								
									d7a0a60053
								
							
						
					
					
						commit
						1d2ff96f6e
					
				
					 7 changed files with 1721 additions and 1667 deletions
				
			
		
							
								
								
									
										372
									
								
								lsp/functions.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										372
									
								
								lsp/functions.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,372 @@ | |||
| 
 | ||||
| 			/** | ||||
| 			 * Show a confirm dialog | ||||
| 			 * @param question the question displayed | ||||
| 			 */ | ||||
|          function confirmDelete(question) | ||||
|          { | ||||
|             return confirm(question); | ||||
|          } | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * Format a date to mm/dd/yyyy hh:mm:ss format | ||||
| 			 * @param date the date to format (timestamp) | ||||
| 			 */ | ||||
|          function formatDate(date) | ||||
|          { | ||||
|             var d = new Date(date * 1000); | ||||
| 
 | ||||
|             return [ | ||||
|                ('00' + d.getMonth()).slice(-2), | ||||
|                ('00' + d.getDate()).slice(-2), | ||||
|                d.getFullYear() | ||||
|             ].join('/') + ' ' + [ | ||||
|                ('00' + d.getHours()).slice(-2), | ||||
|                ('00' + d.getMinutes()).slice(-2), | ||||
|                ('00' + d.getSeconds()).slice(-2) | ||||
|             ].join(':'); | ||||
|          } | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * 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'
 | ||||
| 			 */ | ||||
|          function TypeofResource(uri) | ||||
|          { | ||||
|             var protocol = /([a-zA-Z]+):\/\//.exec(uri); | ||||
| 
 | ||||
|             if(protocol === null || (protocol[1] && protocol[1] === 'file')) | ||||
|             { | ||||
|                return 'Recorded'; | ||||
|             }else{ | ||||
|                return 'Live'; | ||||
|             } | ||||
|          } | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * convert a short limit name to a long one using the table above | ||||
| 			 * @param name the short name of a limit | ||||
| 			 */ | ||||
|          function shortToLongLimit(name) | ||||
|          { | ||||
|             var i; | ||||
| 
 | ||||
|             for(i = 0; i < ltypes.length; i++) | ||||
|             { | ||||
|                if(name == ltypes[i][0]) | ||||
|                { | ||||
|                   return ltypes[i][1]; | ||||
|                } | ||||
|             } | ||||
| 
 | ||||
|             return name; | ||||
|          } | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * forse the server to save to the config file | ||||
| 			 * @param callback function to call after the command is send | ||||
| 			 */ | ||||
|          function forceJSONSave(callback) | ||||
|          { | ||||
| 				// build the object to send to the server
 | ||||
|             var data = | ||||
|             { | ||||
|                'authorize': | ||||
|                { | ||||
|                   'username': settings.credentials.username, | ||||
|                   'password': (settings.credentials.authstring != "" ? MD5(MD5(settings.credentials.password) + settings.credentials.authstring) : "" ) | ||||
|                }, | ||||
|                'save': 1 | ||||
|             }; | ||||
| 
 | ||||
| 				// make the XHR call
 | ||||
|             $.ajax( | ||||
|             { | ||||
|                'url': settings.server, | ||||
|                'data': | ||||
|                { | ||||
|                   "command": JSON.stringify(data) | ||||
|                }, | ||||
|                'dataType': 'jsonp', | ||||
|                'timeout': 10000, | ||||
|                'error': function(){}, | ||||
|                'success': function(){} | ||||
|             }); | ||||
|          } | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * retrieves data from the server ;) | ||||
| 			 * 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. | ||||
| 			 */ | ||||
|          function getData(callback) | ||||
|          { | ||||
|             var data = | ||||
|             { | ||||
|                'authorize': | ||||
|                { | ||||
|                   'username': settings.credentials.username, | ||||
|                   'password': (settings.credentials.authstring != "" ? MD5(MD5(settings.credentials.password) + settings.credentials.authstring) : "" ) | ||||
|                } | ||||
|             }; | ||||
| 
 | ||||
|             $.ajax( | ||||
|             { | ||||
|                'url': settings.server, | ||||
|                'data': | ||||
|                { | ||||
|                   "command": JSON.stringify(data) | ||||
|                }, | ||||
|                'dataType': 'jsonp', | ||||
|                'timeout': 10000, | ||||
|                'error': function(){}, | ||||
|                'success': function(d) | ||||
|                { | ||||
| 
 | ||||
|                   var ret = $.extend(true, | ||||
|                   { | ||||
|                      "streams": {}, | ||||
|                      "statistics": {} | ||||
|                   }, d); | ||||
| 
 | ||||
| 						console.log('[651] RECV', ret); | ||||
| 
 | ||||
|                   if(callback) | ||||
|                   { | ||||
|                      callback(ret); | ||||
|                   } | ||||
|                } | ||||
|             }); | ||||
|          } | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * 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 | ||||
| 			 */ | ||||
| 			function getStreamsData(callback) | ||||
| 			{ | ||||
| 
 | ||||
| 				getData(function(data) | ||||
| 				{ | ||||
| 					var streams = {};   // streamID: [status, numViewers];
 | ||||
| 					var cnt = 0; | ||||
| 
 | ||||
| 					for(var stream in data.streams) | ||||
| 					{ | ||||
| 						streams[stream] = [data.streams[stream].online, 0]; | ||||
| 						cnt++; | ||||
| 					} | ||||
| 
 | ||||
| 					if(cnt === 0) | ||||
| 					{ | ||||
| 						return;   // if there are no streams, don't collect data and just return
 | ||||
| 					} | ||||
| 
 | ||||
| 					for(stream in data.statistics) | ||||
| 					{ | ||||
| 						if(data.statistics[stream].curr) | ||||
| 						{ | ||||
| 							for(var viewer in data.statistics[stream].curr) | ||||
| 							{ | ||||
| 								streams[stream][1]++; | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 
 | ||||
| 					callback(streams); | ||||
| 				}); | ||||
| 			} | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * parses an url and returns the parts of it. | ||||
| 			 * @return object containing the parts of the URL: protocol, host and port. | ||||
| 			 */ | ||||
|          function parseURL(url) | ||||
| 			{ | ||||
| 				var pattern = /(https?)\:\/\/([^:\/]+)\:(\d+)?/; | ||||
| 				 | ||||
| 				var retobj = {protocol: '', host: '', port: ''}; | ||||
| 				var results = url.match(pattern); | ||||
| 
 | ||||
| 				if(results != null) | ||||
| 				{ | ||||
| 			      retobj.protocol = results[1]; | ||||
| 					retobj.host = results[2]; | ||||
| 					retobj.port = results[3]; | ||||
| 				} | ||||
| 
 | ||||
| 				return retobj; | ||||
| 			} | ||||
| 
 | ||||
| 			/** | ||||
| 			 * go figure. | ||||
| 			 * @return true if there is a HTTP connector... and false if there isn't. | ||||
| 			 */ | ||||
| 			function isThereAHTTPConnector() | ||||
| 			{ | ||||
|             var i, | ||||
|                 len = (settings.settings.config.protocols ? settings.settings.config.protocols.length : 0); | ||||
| 
 | ||||
| 				for(i = 0; i < len; i++) | ||||
| 				{ | ||||
| 					if(settings.settings.config.protocols[i].connector == 'HTTP') | ||||
| 					{ | ||||
| 						return true; | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				return false; | ||||
| 			} | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * 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. | ||||
| 			 */ | ||||
|          function getStatData(callback) | ||||
|          { | ||||
|             getData(function(data) | ||||
|             { | ||||
|                var svr, viewer, ret, | ||||
|                    numstr = 0, | ||||
|                    numvwr = 0, | ||||
|                    numtotstr = 0; | ||||
| 
 | ||||
|                for(svr in data.statistics) | ||||
|                { | ||||
|                   if(data.statistics[svr].curr) | ||||
|                   { | ||||
|                      for(viewer in data.statistics[svr].curr) | ||||
|                      { | ||||
|                         numvwr++; | ||||
|                      } | ||||
|                   } | ||||
|                } | ||||
| 
 | ||||
|                for(svr in data.streams) | ||||
|                { | ||||
|                   numtotstr++; | ||||
| 
 | ||||
|                   if(data.streams[svr].online && data.streams[svr].online == 1) | ||||
|                   { | ||||
|                      numstr++; | ||||
|                   } | ||||
|                } | ||||
| 
 | ||||
|                ret = {streams: [numstr, numtotstr], viewers: numvwr}; | ||||
|                callback(ret); | ||||
|             }); | ||||
|          } | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * Connect to the server and retrieve the data | ||||
| 			 * @param callback the function to call when connected. Has one parameter, an optional error string. | ||||
| 			 */ | ||||
|          function loadSettings(callback) | ||||
|          { | ||||
| 				// display 'loading, please wait' while retrieving data
 | ||||
| 				$('body').append( $('<div>').attr('id', 'shield').text('Loading, please wait...') ); | ||||
| 
 | ||||
|             var errorstr = '', | ||||
|                 data = $.extend(settings.settings, | ||||
|                 { | ||||
|                    'authorize': | ||||
|                    { | ||||
|                       'username': settings.credentials.username, | ||||
|                       'password': (settings.credentials.authstring != "" ? MD5(MD5(settings.credentials.password) + settings.credentials.authstring) : "" ) | ||||
|                    } | ||||
|                 }); | ||||
| 
 | ||||
|             delete data.log;   // don't send the logs back to the server
 | ||||
|             delete data.statistics;   // same goes for the stats
 | ||||
| 
 | ||||
|             console.log('[763] SEND', data); | ||||
| 
 | ||||
|             $.ajax( | ||||
|             { | ||||
|                'url': settings.server, | ||||
|                'data': | ||||
|                { | ||||
|                   "command": JSON.stringify(data) | ||||
|                }, | ||||
|                'dataType': 'jsonp', | ||||
| 
 | ||||
|                'timeout': 5000, | ||||
| 
 | ||||
|                'error': function() | ||||
|                { | ||||
|                   showTab('disconnect'); | ||||
| 						$('#shield').remove();   // remove loading display
 | ||||
|                }, | ||||
|                'success': function(d) | ||||
|                { | ||||
| 						$('#shield').remove();   // remove loading display
 | ||||
| 
 | ||||
|                   console.log('[785] RECV', d); | ||||
| 
 | ||||
|                   if(d && d['authorize'] && d['authorize']['challenge']) | ||||
|                   { | ||||
|                      if (settings.credentials.authstring != d['authorize']['challenge']) | ||||
|                      { | ||||
|                         settings.credentials.authstring = d['authorize']['challenge']; | ||||
|                         loadSettings(callback); | ||||
|                         return; | ||||
|                      }else{ | ||||
|                         errorstr = 'wrong credentials'; | ||||
|                      } | ||||
|                   }else{ | ||||
|                      settings.settings = $.extend(true, { | ||||
|                         "config": | ||||
|                         { | ||||
|                            "host": "", | ||||
|                            "limits": [], | ||||
|                            "name": "", | ||||
|                            "protocols": [], | ||||
|                            "status": "", | ||||
|                            "version": "" | ||||
|                         }, | ||||
|                         "streams": {}, | ||||
|                         "log": {}, | ||||
|                         "statistics": {} | ||||
|                      }, d); | ||||
|                   } | ||||
| 
 | ||||
|                   if(callback) | ||||
|                   { | ||||
|                      callback(errorstr); | ||||
|                   } | ||||
|                } | ||||
|             }); | ||||
|          } | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * 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'. | ||||
| 			 */ | ||||
|          function setHeaderState(state) | ||||
|          { | ||||
|             var text, cname, title; | ||||
| 
 | ||||
|             switch(state) | ||||
|             { | ||||
|                case 'logingin':        text = 'connecting...';    cname = 'loggingin';       title = 'connecting to ' + settings.server;     break; | ||||
|                case 'disconnected':    text = 'disconnected';     cname = 'disconnected';    title = 'disconnected';                         break; | ||||
|                case 'connected':       text = 'connected';        cname = 'connected';       title = 'connected to ' + settings.server;      break; | ||||
|             } | ||||
| 
 | ||||
|             document.title = 'Mistserver Manager - ' + title; | ||||
| 
 | ||||
|             $('#header-connection').attr('class', cname); | ||||
|             $('#header-connection').text(text); | ||||
|             $('#header-host').text(settings.server.replace('HTTP://', '')); | ||||
|          } | ||||
| 
 | ||||
							
								
								
									
										1667
									
								
								server.html → lsp/jquery.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1667
									
								
								server.html → lsp/jquery.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										915
									
								
								lsp/main.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										915
									
								
								lsp/main.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,915 @@ | |||
| 
 | ||||
| 
 | ||||
| /*  WERKLOG todolist | ||||
| // TODO FIXME remove deze comment als het klaar is
 | ||||
| settings.settings.statistics[streamID].log (zelfde als curr maar log = gesloten connecties, dus ex-users | ||||
| TODO als server het stuurt | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * Local settings page | ||||
| 			 * DDVTECH | ||||
| 			 * for more information, see http://mistserver.org/index.php?title=Stand-alone_Configuration_Page
 | ||||
| 			 */ | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * Store a local copy of the data send by the server. | ||||
| 			 * server is the URL, credentials hold the username, password and authstring and settings is the local copy. | ||||
| 			 */ | ||||
|          var settings = | ||||
|          { | ||||
|             server: '', | ||||
|             credentials: | ||||
|             { | ||||
|                username: "", | ||||
|                password: "", | ||||
|                authstring: "" | ||||
|             }, | ||||
|             settings: {} | ||||
|          }; | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 *  Table for long/short limit names | ||||
| 			 */ | ||||
|          var ltypes = | ||||
|          [ | ||||
|             ['kb_total', 'Total bandwidth'], | ||||
|             ['kbps_max', 'Current bandwidth'], | ||||
|             ['users', 'Concurrent users'], | ||||
|             ['streams', 'Cocurrent streams'], | ||||
|             ['geo', 'Geolimited'], | ||||
|             ['host', 'Hostlimited'], | ||||
|             ['time', 'Timelimited'], | ||||
|             ['duration', 'Duration'], | ||||
|             ['str_kbps_min', 'Minimum bitrate'], | ||||
|             ['str_kbps_max', 'Maximum bitrate'] | ||||
|          ]; | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 *  When the page loads, fix the menu and show the correct tab | ||||
| 			 */ | ||||
|          $(document).ready(function() | ||||
|          { | ||||
|             $('#nav').children().each(function() | ||||
|             { | ||||
|                $(this).click(function() | ||||
|                { | ||||
|                   // remove currently selected' class
 | ||||
|                   $('#nav').children().each(function() | ||||
|                   { | ||||
|                      $(this).attr('class', ''); | ||||
|                   }); | ||||
| 
 | ||||
|                   // select this one
 | ||||
|                   $(this).attr('class', 'selected'); | ||||
| 
 | ||||
|                   // show correct tab
 | ||||
|                   showTab($(this).text()); | ||||
|                }); | ||||
|             }); | ||||
| 
 | ||||
|             // show login 'tab' and hide menu
 | ||||
|             showTab('login'); | ||||
|             $('#nav').css('visibility', 'hidden'); | ||||
|          }); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|          // used on the overview and streams page. cleared when switching to another 'tab'.
 | ||||
|          var sinterval = null; | ||||
| 
 | ||||
|          // what kind of streams should be displayed? Format is [recorded, live];
 | ||||
|          var streamsdisplay = [true, true]; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 			/** | ||||
| 			 * Display a certain page. It contains a (giant) switch-statement, that builds a page depending on the tab requested | ||||
| 			 * @param name the name of the tab | ||||
| 			 * @param streamname only used when editing streams, the name of the edited (or new) stream. Also used with the 'embed' tab | ||||
| 			 */ | ||||
|          function showTab(name, streamname) | ||||
|          { | ||||
|             // clear page and refresh interval
 | ||||
|             $('#page').html(''); | ||||
|             clearInterval(sinterval); | ||||
| 
 | ||||
|             switch(name) | ||||
|             { | ||||
|                case 'login': | ||||
| 
 | ||||
|                   var host = $('<input>').attr('type', 'text').attr('placeholder', 'HTTP://LOCALHOST:4242'); | ||||
|                   var user = $('<input>').attr('type', 'text').attr('placeholder', 'USERNAME'); | ||||
|                   var pass = $('<input>').attr('type', 'password').attr('placeholder', 'PASSWORD'); | ||||
|                   var conn = $('<button>').click(function() | ||||
|                   { | ||||
|                      // get login info
 | ||||
|                      settings.credentials.username = user.val(); | ||||
|                      settings.credentials.password = pass.val(); | ||||
|                      settings.server = host.val() || host.attr('placeholder'); | ||||
| 
 | ||||
|                      // save username, URL in address
 | ||||
|                      location.hash = user.val() + '@' + host.val(); | ||||
| 
 | ||||
|                      // try to login
 | ||||
|                      setHeaderState('logingin'); | ||||
| 
 | ||||
|                      loadSettings(function(errorstr) | ||||
|                      { | ||||
|                         if(errorstr == '') | ||||
|                         { | ||||
|                            setHeaderState('connected'); | ||||
| 
 | ||||
|                            $('#nav').css('visibility', 'visible'); | ||||
| 
 | ||||
|                            showTab('overview'); | ||||
| 
 | ||||
|                            // show overview as current tab - this only happens when logging out and then in
 | ||||
|                            $('#nav').children().each(function() | ||||
|                            { | ||||
|                               if($(this).text() != 'overview') | ||||
|                               { | ||||
|                                  $(this).attr('class', ''); | ||||
|                               }else{ | ||||
|                                  $(this).attr('class', 'selected'); | ||||
|                               } | ||||
|                            }); | ||||
| 
 | ||||
|                         }else{ | ||||
|                            setHeaderState('disconnected'); | ||||
|                            $('#header-host').text(''); | ||||
|                         } | ||||
|                      }); | ||||
|                   }).text('login'); | ||||
| 
 | ||||
|                   $('#page').append( | ||||
|                      $('<div>').attr('id', 'login').append(host).append(user).append(pass).append(conn) | ||||
|                   ); | ||||
| 
 | ||||
|                   // if we 'enter' in host, user or pass we should try to login.
 | ||||
|                   function hand(e) | ||||
|                   { | ||||
|                      if(e.keyCode == 13) | ||||
|                      { | ||||
|                         conn.trigger('click');  // conn = login button
 | ||||
|                      } | ||||
|                   } | ||||
| 
 | ||||
|                   host.keypress(hand); | ||||
|                   user.keypress(hand); | ||||
|                   pass.keypress(hand); | ||||
| 
 | ||||
|                   // retrieve address hash from URL
 | ||||
|                   var adr = location.hash.replace('#', '').split('@'); | ||||
| 
 | ||||
|                   if(adr.length == 2) | ||||
|                   { | ||||
|                      // put it in the page
 | ||||
|                      host.val(adr[1]); | ||||
|                      user.val(adr[0]); | ||||
|                   } | ||||
| 
 | ||||
|                   break; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                case 'overview': | ||||
| 
 | ||||
|                   $('#page').append( | ||||
|                      $('<div>').attr('id', 'editserver').append( | ||||
|                         $('<label>').attr('for', 'config-host').text('host').append( | ||||
|                            $('<input>').attr('type', 'text').attr('placeholder', 'HOST').attr('id', 'config-host').attr('value', settings.settings.config.host) | ||||
|                         ) | ||||
|                      ).append( | ||||
|                         $('<label>').attr('for', 'config-name').text('name').append( | ||||
|                            $('<input>').attr('type', 'text').attr('placeholder', 'NAME').attr('id', 'config-name').attr('value', settings.settings.config.name) | ||||
|                         ) | ||||
|                      ).append( | ||||
|                         $('<label>').text('version').append( | ||||
|                            $('<span>').text(settings.settings.config.version) | ||||
|                         ) | ||||
|                      ).append( | ||||
|                         $('<label>').text('time').append( | ||||
|                            $('<span>').text( formatDate(settings.settings.config.time) ) | ||||
|                         ) | ||||
|                      ).append( | ||||
|                         $('<label>').text('Streams').append( | ||||
|                            $('<span>').attr('id', 'cur_streams_online').text('retrieving data...') | ||||
|                         ) | ||||
|                      ).append( | ||||
|                         $('<label>').text('Viewers').append( | ||||
|                            $('<span>').attr('id', 'cur_num_viewers').text('retrieving data...') | ||||
|                         ) | ||||
|                      ) | ||||
|                   ); | ||||
| 
 | ||||
|                   function showStats() | ||||
|                   { | ||||
|                      getStatData(function(data) | ||||
|                      { | ||||
|                         $('#cur_streams_online').html('').text(data.streams[0] + ' of ' + data.streams[1] + ' online'); | ||||
|                         $('#cur_num_viewers').html('').text(data.viewers); | ||||
|                      }); | ||||
|                   } | ||||
| 
 | ||||
| 						// refresh the stream status + viewers
 | ||||
|                   sinterval = setInterval(function() | ||||
|                   { | ||||
|                      showStats(); | ||||
|                   }, 10000); | ||||
| 
 | ||||
|                   showStats(); | ||||
| 
 | ||||
| 
 | ||||
|                   $('#editserver').append( | ||||
|                      $('<button>').attr('class', 'floatright').click(function() | ||||
|                      { | ||||
|                         var host = $('#config-host').val(); | ||||
|                         var name = $('#config-name').val(); | ||||
| 
 | ||||
|                         settings.settings.config.host = host; | ||||
|                         settings.settings.config.name = name; | ||||
| 
 | ||||
|                         loadSettings(function() | ||||
|                         { | ||||
|                            showTab('overview'); | ||||
|                         }); | ||||
|                      }).text( 'save' ) | ||||
|                   ); | ||||
| 
 | ||||
| 
 | ||||
|                   var forcesave = $('<div>').attr('id', 'forcesave'); | ||||
| 
 | ||||
|                   forcesave.append( | ||||
|                      $('<p>').text('Click the button below to force an immediate settings save. This differs from a regular save to memory and file save on exit by saving directly to file while operating. This may slow server processes for a short period of time.') | ||||
|                   ).append( | ||||
|                      $('<button>').click(function() | ||||
|                      { | ||||
|                        if(confirmDelete('Are you sure you want to force a JSON save?') == true) | ||||
|                        { | ||||
|                           forceJSONSave(); | ||||
|                        } | ||||
|                      }).text( 'force save to JSON file' ) | ||||
|                   ); | ||||
| 
 | ||||
|                   $('#page').append(forcesave); | ||||
| 
 | ||||
|                   break; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                case 'protocols': | ||||
| 
 | ||||
|                   $table = $('<table>'); | ||||
|                   $table.html("<thead><th>Protocol</th><th>Port</th><th>Interface</th><th></th></thead>"); | ||||
|                   $tbody = $('<tbody>'); | ||||
| 
 | ||||
|                   var tr, i, protocol, | ||||
|                       len = (settings.settings.config.protocols ? settings.settings.config.protocols.length : 0); | ||||
| 
 | ||||
|                   $tbody.html(''); | ||||
| 
 | ||||
|                   for(i = 0; i < len; i++) | ||||
|                   { | ||||
|                      protocol = settings.settings.config.protocols[i];  // local copy
 | ||||
| 
 | ||||
|                      tr = $('<tr>').attr('id', 'protocol-' + i); | ||||
| 
 | ||||
|                      tr.append( $('<td>').text( protocol.connector ) ); | ||||
|                      tr.append( $('<td>').text( protocol.port ) ); | ||||
| 
 | ||||
|                      tr.append( $('<td>').text( protocol['interface'] ) );  // interface is a reserved JS keyword
 | ||||
| 
 | ||||
|                      tr.append( $('<td>').attr('class', 'center').append( $('<button>').click(function() | ||||
| 		                 { | ||||
| 		                    if(confirmDelete('Are you sure you want to delete this protocol?') == true) | ||||
| 		                    { | ||||
| 		                       var id = $(this).parent().parent().attr('id').replace('protocol-', ''); | ||||
| 		                       settings.settings.config.protocols.splice(id, 1); | ||||
| 		                       $(this).parent().parent().remove(); | ||||
| 		                       loadSettings(); | ||||
| 		                    } | ||||
| 		                 }).text('delete') ) ); | ||||
| 
 | ||||
|                      $tbody.append(tr); | ||||
|                   } | ||||
| 
 | ||||
| 
 | ||||
|                   // add new protocol!
 | ||||
|                   $nprot = $('<tr>').attr('class', 'outsidetable'); | ||||
|                   // protocol select
 | ||||
|                   $pname = $('<select>').attr('id', 'new-protocol-name'); | ||||
|                   $pname.append( $('<option>').attr('value', 'HTTP').text('HTTP') ); | ||||
|                   $pname.append( $('<option>').attr('value', 'RTMP').text('RTMP') ); | ||||
| 
 | ||||
|                   $nprot.append( $('<td>').append($pname) ); | ||||
|                   // the port value
 | ||||
|                   $nprot.append( $('<td>').append( $('<input>').attr('type', 'number').attr('id', 'new-protocol-val') ) ); | ||||
| 
 | ||||
|                   // interface
 | ||||
|                   $nprot.append( $('<td>').append( $('<input>').attr('type', 'text').attr('id', 'new-protocol-interface') ) ); | ||||
| 
 | ||||
|                   $nprot.append( | ||||
|                      $('<td>').attr('class', 'center').append( | ||||
|                         $('<button>').click(function() | ||||
|                         { | ||||
|                            if($('#new-protocol-val').val() == '') | ||||
|                            { | ||||
|                               $('#new-protocol-val').focus(); | ||||
|                               return; | ||||
|                            } | ||||
| 
 | ||||
|                            if(!settings.settings.config.protocols) | ||||
|                            { | ||||
|                               settings.settings.config.protocols = []; | ||||
|                            } | ||||
| 
 | ||||
|                            var nobj = | ||||
|                            { | ||||
|                               connector: $('#new-protocol-name :selected').val(), | ||||
|                               port: Math.abs($('#new-protocol-val').val()), | ||||
|                            }; | ||||
| 
 | ||||
|                            nobj['interface'] = $('#new-protocol-interface').val(); | ||||
| 
 | ||||
|                            settings.settings.config.protocols.push(nobj); | ||||
| 
 | ||||
|                            loadSettings(function() | ||||
|                            { | ||||
|                               showTab('protocols'); | ||||
|                            }); | ||||
| 
 | ||||
|                         }).text('add new') | ||||
|                      ) | ||||
|                   ); | ||||
| 
 | ||||
|                   $tbody.append($nprot); | ||||
|                   $table.append($tbody); | ||||
|                   $('#page').append($table); | ||||
| 
 | ||||
|                   break; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                case 'streams': | ||||
| 
 | ||||
|                   // the filter element containr
 | ||||
|                   $div = $('<div>').attr('id', 'streams-filter'); | ||||
| 
 | ||||
| 						// filters the table. uses the streamsdisplay
 | ||||
|                   function filterTable() | ||||
|                   { | ||||
|                      $('#streams-list-tbody').children().each(function(k, v) | ||||
|                      { | ||||
|                         var type = $($(v).children()[0]).text().toLowerCase(); | ||||
| 
 | ||||
|                         $(v).show(); | ||||
| 
 | ||||
|                         if(type == 'recorded' && streamsdisplay[0] == false) | ||||
|                         { | ||||
|                            $(v).hide(); | ||||
|                         } | ||||
| 
 | ||||
|                         if(type == 'live' && streamsdisplay[1] == false) | ||||
|                         { | ||||
|                            $(v).hide(); | ||||
|                         } | ||||
|                      }); | ||||
|                   } | ||||
| 
 | ||||
|                   function filterOn(event, elem) | ||||
|                   { | ||||
|                      if(event.target.id == '') | ||||
|                      { | ||||
|                         return;  // label click goes bubbles on checkbox, so ignore it
 | ||||
|                      } | ||||
| 
 | ||||
|                      var what = $(elem).text(); | ||||
| 
 | ||||
|                      if(what == 'recorded') | ||||
|                      { | ||||
|                         streamsdisplay[0] = !streamsdisplay[0]; | ||||
|                         $('#stream-filter-recorded').attr('checked', streamsdisplay[0]); | ||||
|                      }else{ | ||||
|                         streamsdisplay[1] = !streamsdisplay[1]; | ||||
|                         $('#stream-filter-live').attr('checked', streamsdisplay[1]); | ||||
|                      } | ||||
| 
 | ||||
|                      filterTable(); | ||||
|                   } | ||||
| 
 | ||||
|                   $div.append( | ||||
|                      $('<label>').attr('for', 'stream-filter-recorded').text('recorded').append( | ||||
|                         $('<input>').attr('type', 'checkbox').attr('id', 'stream-filter-recorded').attr('checked', streamsdisplay[0]) | ||||
|                      ).click(function(event) | ||||
|                      { | ||||
|                         filterOn(event, this); | ||||
|                      }) | ||||
|                   ); | ||||
|                   $div.append( | ||||
|                      $('<label>').attr('for', 'stream-filter-live').text('live').append( | ||||
|                         $('<input>').attr('type', 'checkbox').attr('id', 'stream-filter-live').attr('checked', streamsdisplay[1]) | ||||
|                      ).click(function(event) | ||||
|                      { | ||||
|                         filterOn(event, this); | ||||
|                      }) | ||||
|                   ); | ||||
| 
 | ||||
|                   $('#page').append($div); | ||||
| 
 | ||||
| 						// refresh every streams' data (status and viewer count)
 | ||||
| 						function refreshStreams() | ||||
| 						{ | ||||
| 							getStreamsData(function(streams) | ||||
| 							{ | ||||
| 								for(stream in streams) | ||||
| 								{ | ||||
| 									if( $('stream-' + stream) ) | ||||
| 									{ | ||||
| 										var row = $('#stream-' + stream); | ||||
| 										var status = streams[stream][0]; | ||||
| 
 | ||||
| 										if(status == 1) | ||||
| 										{ | ||||
| 											$(row.children()[3]).html("<span class='green'>Running</span>"); | ||||
| 										}else{ | ||||
| 											$(row.children()[3]).html("<span class='red'>" + (status ? status : 'Offline') + "</span>"); | ||||
| 										} | ||||
| 
 | ||||
| 										$(row.children()[4]).text(streams[stream][1]); | ||||
| 									} | ||||
| 								} | ||||
| 							}); | ||||
| 						}; | ||||
| 
 | ||||
| 						sinterval = setInterval(function() | ||||
| 						{ | ||||
| 							refreshStreams(); | ||||
| 						}, 10000); | ||||
| 
 | ||||
| 						refreshStreams(); | ||||
| 
 | ||||
|                   $table = $('<table>'); | ||||
|                   $table.html("<thead><th>Type</th><th>Embed</th><th>Name</th><th>Status</th><th>Viewers</th><th>Edit</th></thead>"); | ||||
|                   $tbody = $('<tbody>'); | ||||
| 
 | ||||
|                   var stream, cstr, $tr; | ||||
| 
 | ||||
|                   $tbody.html('').attr('id', 'streams-list-tbody'); | ||||
| 
 | ||||
|                   for(stream in settings.settings.streams) | ||||
|                   { | ||||
|                      var cstr = settings.settings.streams[stream]; | ||||
| 
 | ||||
|                      $tr = $('<tr>').attr('id', 'stream-' + stream); | ||||
| 
 | ||||
|                      $tr.append( $('<td>').text( TypeofResource( cstr.channel.URL ) ) ); | ||||
| 
 | ||||
|                      $tr.append( $('<td>').append( $('<button>').text('embed').click(function() | ||||
|                      { | ||||
|                         var sname = $(this).parent().parent().attr('id').replace('stream-', ''); | ||||
|                         showTab('embed', sname); | ||||
|                      }) ) );   // end function, end click(), end append(), end append(). Huzzah jQuery.
 | ||||
| 
 | ||||
|                      $tr.append( $('<td>').text(cstr.name) ); | ||||
| 
 | ||||
|                      if(cstr.online && cstr.online == 1) | ||||
|                      { | ||||
|                         $tr.append( $('<td>').html("<span class='green'>Running</span>") ); | ||||
|                      }else{ | ||||
|                         $tr.append( $('<td>').html("<span class='red'>" + (cstr.online ? cstr.online : 'Offline') + "</span>") ); | ||||
|                      } | ||||
| 
 | ||||
|                      var cviewers = 0; | ||||
| 
 | ||||
|                      if(settings.settings.statistics && settings.settings.statistics[stream]) | ||||
|                      { | ||||
|                         if(settings.settings.statistics[stream] && settings.settings.statistics[stream].curr) | ||||
|                         { | ||||
|                            for(viewer in settings.settings.statistics[stream].curr) | ||||
|                            { | ||||
|                               cviewers++; | ||||
|                            } | ||||
|                         } | ||||
|                      }else{ | ||||
|                         cviewers = 0; | ||||
|                      } | ||||
| 
 | ||||
|                      $tr.append( $('<td>').text( cviewers ) ); | ||||
| 
 | ||||
|                      $tr.append( $('<td>').append( $('<button>').text('edit').click(function() | ||||
|                      { | ||||
|                         var sname = $(this).parent().parent().attr('id').replace('stream-', ''); | ||||
| 
 | ||||
|                         showTab('editstream', sname); | ||||
|                      }) ) );   // end function, end click, end append, end append.
 | ||||
| 
 | ||||
|                      $tbody.append($tr); | ||||
|                   } | ||||
| 
 | ||||
|                   $table.append($tbody); | ||||
|                   $('#page').append($table); | ||||
| 
 | ||||
|                   // on page load, also filter with the (users' defined) stream filter
 | ||||
|                   filterTable(); | ||||
| 
 | ||||
|                   $('#page').append( | ||||
|                      $('<button>').attr('class', 'floatright').click(function() | ||||
|                      { | ||||
|                         showTab('editstream', 'new'); | ||||
|                      }).text('add new') | ||||
|                   ); | ||||
| 
 | ||||
|                   break; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                case 'editstream': | ||||
| 
 | ||||
|                   var sdata, title; | ||||
| 
 | ||||
|                   if(streamname == 'new') | ||||
|                   { | ||||
|                      sdata = | ||||
|                      { | ||||
|                         name: '', | ||||
|                         channel: | ||||
|                         { | ||||
|                            URL: '' | ||||
|                         }, | ||||
|                         limits: [], | ||||
|                         preset: | ||||
|                         { | ||||
|                            cmd: '' | ||||
|                         } | ||||
|                      }; | ||||
|                      title = 'add new stream'; | ||||
|                   }else{ | ||||
|                      sdata = settings.settings.streams[streamname]; | ||||
|                      title = 'edit stream "' + sdata.name + '"'; | ||||
|                   } | ||||
| 
 | ||||
|                   $('#page').append( $('<p>').text(title) ); | ||||
| 
 | ||||
|                   $('#page').append( | ||||
|                      $('<div>').attr('id', 'editserver').append( | ||||
|                         $('<label>').attr('for', 'stream-edit-name').text('name').append( | ||||
|                            $('<input>').attr('type', 'text').attr('placeholder', 'NAME').attr('id', 'stream-edit-name').attr('value', sdata.name) | ||||
|                         ) | ||||
|                      ).append( | ||||
|                         $('<label>').attr('for', 'stream-edit-source').text('source').append( | ||||
|                            $('<input>').attr('type', 'text').attr('placeholder', 'SOURCE').attr('id', 'stream-edit-source').attr('value', sdata.channel.URL).keyup(function() | ||||
| 									{ | ||||
| 									   var text = $(this).val(); | ||||
| 
 | ||||
| 										if(text.charAt(0) == '/' || text.substr(0, 7) == 'push://') | ||||
| 										{ | ||||
| 											$('#stream-edit-preset').val(''); | ||||
| 											$('#stream-edit-preset').hide(); | ||||
| 											$('#stream-edit-preset-label').hide(); | ||||
| 										}else{ | ||||
| 											$('#stream-edit-preset').show(); | ||||
| 											$('#stream-edit-preset-label').show(); | ||||
| 										} | ||||
| 									}) | ||||
|                         ) | ||||
|                      ).append( | ||||
|                         $('<label>').attr('id', 'stream-edit-preset-label').attr('for', 'stream-edit-preset').text('preset').append( | ||||
|                            $('<input>').attr('type', 'text').attr('placeholder', 'PRESET').attr('id', 'stream-edit-preset').attr('value', sdata.preset.cmd) | ||||
|                         ) | ||||
|                      ) | ||||
|                   ); | ||||
| 
 | ||||
| 						// if the source is push or file, don't do a preset
 | ||||
| 					   var text = $('#stream-edit-source').val(); | ||||
| 
 | ||||
| 						if(text.charAt(0) == '/' || text.substr(0, 7) == 'push://') | ||||
| 						{ | ||||
| 							$('#stream-edit-preset').hide(); | ||||
| 							$('#stream-edit-preset-label').hide(); | ||||
| 						}else{ | ||||
| 							$('#stream-edit-preset').show(); | ||||
| 							$('#stream-edit-preset-label').show(); | ||||
| 						} | ||||
| 
 | ||||
| 
 | ||||
|                   $('#editserver').append( | ||||
|                      $('<button>').attr('class', 'floatright').click(function() | ||||
|                      { | ||||
|                         if(streamname == 'new') | ||||
|                         { | ||||
|                            showTab('streams'); | ||||
|                         }else{ | ||||
|                            if(confirmDelete('Are you sure you want to delete the stream "' + settings.settings.streams[streamname].name + '"?') == true) | ||||
|                            { | ||||
|                               delete settings.settings.streams[streamname]; | ||||
|                               loadSettings(function() | ||||
|                               { | ||||
|                                  showTab('streams'); | ||||
|                               }); | ||||
|                            } | ||||
|                         } | ||||
|                      }).text( streamname == 'new' ? 'cancel' : 'delete' ) | ||||
|                   ); | ||||
| 
 | ||||
|                   $('#editserver').append( | ||||
|                      $('<button>').attr('class', 'floatright').click(function() | ||||
|                      { | ||||
|                         var n = $('#stream-edit-name'); | ||||
|                         var s = $('#stream-edit-source'); | ||||
|                         var p = $('#stream-edit-preset'); | ||||
| 
 | ||||
|                         if(n.val() == ''){ n.focus(); return; } | ||||
|                         if(s.val() == ''){ s.focus(); return; } | ||||
| 
 | ||||
|                         sdata.name = n.val(); | ||||
|                         sdata.channel.URL = s.val(); | ||||
|                         sdata.preset.cmd = p.val(); | ||||
| 
 | ||||
|                         if(streamname == 'new') | ||||
|                         { | ||||
|                            streamname = n.val().replace(/ /g, '-'); | ||||
|                         } | ||||
| 
 | ||||
|                         if(!settings.settings.streams) | ||||
|                         { | ||||
|                            settings.settings.streams = {}; | ||||
|                         } | ||||
| 
 | ||||
|                         settings.settings.streams[streamname] = sdata; | ||||
| 
 | ||||
|                         loadSettings(function() | ||||
|                         { | ||||
|                            showTab('streams'); | ||||
|                         }); | ||||
|                             | ||||
|                      }).text('save') | ||||
|                   ); | ||||
| 
 | ||||
|                   break; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                case 'embed': | ||||
| 
 | ||||
| 						if(isThereAHTTPConnector()) | ||||
| 						{ | ||||
| 							var embed = 'http://' + parseURL(settings.server).host + ':8080/embed_' + streamname + '.js'; | ||||
| 
 | ||||
| 							$('#page').append( $('<p>').attr('class', 'nocapitals').text('The embed URL is "' + embed + '".') ); | ||||
| 
 | ||||
| 							$('#page').append( $('<button>').text('preview').click(function() | ||||
| 							{ | ||||
| 								showTab('preview', streamname); | ||||
| 							} ) ); | ||||
| 
 | ||||
| 						}else{ | ||||
| 							$('#page').append( $('<p>').attr('class', 'nocapitals').text('Could\'t find a HTTP connector. Please add a HTTP connector on the "protocol" page.') ); | ||||
| 						} | ||||
| 
 | ||||
|                   break; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                case 'preview': | ||||
| 
 | ||||
| 						var embed = 'http://' + parseURL(settings.server).host + ':8080/embed_' + streamname + '.js'; | ||||
| 
 | ||||
| 						$('#page').append( $('<div>').html( "<script src='" + embed + "'></script>" ) ); | ||||
| 
 | ||||
|                   break; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                case 'limits': | ||||
|                   $table = $('<table>'); | ||||
|                   $table.html("<thead><th>Type</th><th>Hard/soft</th><th>Value</th><th>applies to</th><th>Action</th></thead>"); | ||||
|                   $tbody = $('<tbody>'); | ||||
| 
 | ||||
|                   var i, tr, limit, stream, clims, | ||||
|                       alllimits = settings.settings.config.limits; | ||||
| 
 | ||||
|                   for(stream in settings.settings.streams) | ||||
|                   { | ||||
|                      clims = settings.settings.streams[stream].limits; | ||||
| 
 | ||||
|                      $.each(clims, function(k, v) | ||||
|                      { | ||||
|                         this.appliesto = stream; | ||||
|                         this.appliesi = k; | ||||
|                      }); | ||||
| 
 | ||||
|                      alllimits = alllimits.concat(clims); | ||||
|                   } | ||||
| 
 | ||||
|                   len = alllimits.length; | ||||
| 
 | ||||
|                   // remove old items
 | ||||
|                   $tbody.html(''); | ||||
| 
 | ||||
|                   for(i = 0; i < len; i++) | ||||
|                   { | ||||
|                      tr = $('<tr>').attr('id', 'limits-' + i); | ||||
|                      limit = alllimits[i]; | ||||
| 
 | ||||
|                      tr.append( $('<td>').text( shortToLongLimit(limit.name) ) ); | ||||
|                      tr.append( $('<td>').text( limit.type ) ); | ||||
|                      tr.append( $('<td>').text( limit.val ) ); | ||||
| 
 | ||||
| 
 | ||||
|                      if(limit.appliesto) | ||||
|                      { | ||||
|                         tr.append( $('<td>').text( settings.settings.streams[limit.appliesto].name ).attr('id', 'limit-at-' + limit.appliesto + '-' + limit.appliesi) ); | ||||
|                      }else{ | ||||
|                         tr.append( $('<td>').text( 'server' ) ); | ||||
|                      } | ||||
| 
 | ||||
|                      delete limit.appliesto; | ||||
|                      delete limit.appliesi; | ||||
| 
 | ||||
|                      tr.append( $('<td>').attr('class', 'center').append( $('<button>').click(function() | ||||
|                                 { | ||||
|                                    if(confirmDelete('Are you sure you want to delete this limit?') == true) | ||||
|                                    { | ||||
|                                       var id = $(this).parent().parent().attr('id').replace('limits-', ''); | ||||
|                                       var at = $($(this).parent().parent().children()[3]).attr('id'); | ||||
| 
 | ||||
|                                       if(at == undefined) | ||||
|                                       { | ||||
|                                          settings.settings.config.limits.splice(id, 1); | ||||
|                                       }else{ | ||||
|                                          var data = at.replace('limit-at-', '').split('-'); | ||||
|                                          var loc = data.pop(); | ||||
|                                          data = data.join('-'); | ||||
| 
 | ||||
|                                          settings.settings.streams[data].limits.splice(loc, 1); | ||||
|                                       } | ||||
| 
 | ||||
|                                       $(this).parent().parent().remove(); | ||||
| 
 | ||||
|                                       loadSettings(); | ||||
|                                    } | ||||
|                                 }).text('delete') ) ); | ||||
| 
 | ||||
|                      $tbody.append(tr); | ||||
|                   } | ||||
| 
 | ||||
|                   // add new limit
 | ||||
|                   $nltr = $('<tr>').attr('class', 'outsidetable'); | ||||
| 
 | ||||
|                   // type selector
 | ||||
|                   $ltype = $('<select>').attr('id', 'new-limit-type'); | ||||
|                   for(i = 0; i < ltypes.length; i++) | ||||
|                   { | ||||
|                      $ltype.append( $('<option>').attr('value', ltypes[i][0]).text(ltypes[i][1]) ); | ||||
|                   } | ||||
|                   $nltr.append( $('<td>').append( $ltype ) ); | ||||
|                   // hard/soft limit
 | ||||
|                   $nltr.append( $('<td>').append( $('<select>').attr('id', 'new-limit-hs').append( $('<option>').attr('value', 'hard').text('Hard limit') ).append( $('<option>').attr('value', 'soft').text('Soft limit') ) ) ); | ||||
|                   // value
 | ||||
|                   $nltr.append( $('<td>').append( $('<input>').attr('type', 'text').attr('id', 'new-limit-val') ) ); | ||||
| 
 | ||||
|                   // applies to (stream)
 | ||||
|                   var $appliesto = $('<select>').attr('id', 'new-limit-appliesto').append( $('<option>').attr('value', 'server').text('Server') ); | ||||
| 
 | ||||
|                   for(var strm in settings.settings.streams) | ||||
|                   { | ||||
|                      $appliesto.append( | ||||
|                         $('<option>').attr('value', strm).text(settings.settings.streams[strm].name) | ||||
|                      ); | ||||
|                   } | ||||
|                   $nltr.append( $('<td>').append( $appliesto ) ); | ||||
| 
 | ||||
|                   $nltr.append( | ||||
|                      $('<td>').attr('class', 'center').append( | ||||
|                         $('<button>').click(function() | ||||
|                         { | ||||
|                            var obj = | ||||
|                            { | ||||
|                               name: $('#new-limit-type :selected').val(), | ||||
|                               type: $('#new-limit-hs :selected').val(), | ||||
|                               val:  $('#new-limit-val').val() | ||||
|                            }; | ||||
| 
 | ||||
|                            if( $('#new-limit-appliesto').val() == 'server') | ||||
|                            { | ||||
|                               settings.settings.config.limits.push(obj); | ||||
|                            }else{ | ||||
|                               settings.settings.streams[ $('#new-limit-appliesto').val() ].limits.push(obj); | ||||
|                            } | ||||
| 
 | ||||
|                            loadSettings(function() | ||||
|                            { | ||||
|                               showTab('limits'); | ||||
|                            }); | ||||
| 
 | ||||
|                         }).text('add new') | ||||
|                      ) | ||||
|                   ); | ||||
|                   $tbody.append($nltr); | ||||
| 
 | ||||
|                   $table.append($tbody); | ||||
|                   $('#page').append($table); | ||||
| 
 | ||||
|                   break; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                case 'logs': | ||||
|                   $table = $('<table>'); | ||||
|                   $table.html("<thead><th>Date<span class='theadinfo'>(MM/DD/YYYY)</span></th><th>Type</th><th>Message</th></thead>"); | ||||
|                   $tbody = $('<tbody>'); | ||||
| 
 | ||||
| 						if(!settings.settings.log) | ||||
| 						{ | ||||
| 							return;  // no logs, so just bail
 | ||||
| 						} | ||||
|                   var i, cur, $tr, | ||||
|                       logs = settings.settings.log, | ||||
|                       len = logs.length; | ||||
| 
 | ||||
|                   if(len >= 2 && settings.settings.log[0][0] < settings.settings.log[len - 1][0]) | ||||
|                   { | ||||
|                      logs.reverse(); | ||||
|                   } | ||||
| 
 | ||||
|                   $tbody.html(''); | ||||
| 
 | ||||
|                   for(i = 0; i < len; i++) | ||||
|                   { | ||||
|                      cur = settings.settings.log[i]; | ||||
| 
 | ||||
|                      $tr = $('<tr>').append( | ||||
|                         $('<td>').text(formatDate(cur[0])) | ||||
|                      ).append( | ||||
|                         $('<td>').text(cur[1]) | ||||
|                      ).append( | ||||
|                         $('<td>').text(cur[2]) | ||||
|                      ); | ||||
| 
 | ||||
|                      $tbody.append($tr); | ||||
|                   } | ||||
| 
 | ||||
|                   $table.append($tbody); | ||||
|                   $('#page').append($table); | ||||
| 
 | ||||
|                   $('#page').append( | ||||
|                      $('<button>').attr('class', 'floatright').click(function() | ||||
|                      { | ||||
|                         settings.settings.clearstatlogs = 1; | ||||
|                         loadSettings(function() | ||||
|                         { | ||||
|                            showTab('logs'); | ||||
|                         }); | ||||
|                      }).text('Purge logs') | ||||
|                   ); | ||||
| 
 | ||||
|                   break; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                case 'disconnect': | ||||
|                   showTab('login'); | ||||
|                   setHeaderState('disconnected'); | ||||
|                   $('#nav').css('visibility', 'hidden'); | ||||
| 
 | ||||
|                   settings = | ||||
|                   { | ||||
|                      server: '', | ||||
|                      credentials: | ||||
|                      { | ||||
|                         username: "", | ||||
|                         password: "", | ||||
|                         authstring: "" | ||||
|                      }, | ||||
|                      settings: {} | ||||
|                   }; | ||||
|                   break; | ||||
| 
 | ||||
|             }  // end switch
 | ||||
| 
 | ||||
| 
 | ||||
|             //placeholder for older browsers
 | ||||
|             $('input[placeholder]').placeholder(); | ||||
| 
 | ||||
|          } | ||||
| 
 | ||||
							
								
								
									
										2
									
								
								lsp/md5.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								lsp/md5.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| var MD5=function(j){function RotateLeft(a,b){return(a<<b)|(a>>>(32-b))}function AddUnsigned(a,b){var c,lY4,lX8,lY8,lResult;lX8=(a&0x80000000);lY8=(b&0x80000000);c=(a&0x40000000);lY4=(b&0x40000000);lResult=(a&0x3FFFFFFF)+(b&0x3FFFFFFF);if(c&lY4){return(lResult^0x80000000^lX8^lY8)}if(c|lY4){if(lResult&0x40000000){return(lResult^0xC0000000^lX8^lY8)}else{return(lResult^0x40000000^lX8^lY8)}}else{return(lResult^lX8^lY8)}}function F(x,y,z){return(x&y)|((~x)&z)}function G(x,y,z){return(x&z)|(y&(~z))}function H(x,y,z){return(x^y^z)}function I(x,y,z){return(y^(x|(~z)))}function FF(a,b,c,d,x,s,e){a=AddUnsigned(a,AddUnsigned(AddUnsigned(F(b,c,d),x),e));return AddUnsigned(RotateLeft(a,s),b)};function GG(a,b,c,d,x,s,e){a=AddUnsigned(a,AddUnsigned(AddUnsigned(G(b,c,d),x),e));return AddUnsigned(RotateLeft(a,s),b)};function HH(a,b,c,d,x,s,e){a=AddUnsigned(a,AddUnsigned(AddUnsigned(H(b,c,d),x),e));return AddUnsigned(RotateLeft(a,s),b)};function II(a,b,c,d,x,s,e){a=AddUnsigned(a,AddUnsigned(AddUnsigned(I(b,c,d),x),e));return AddUnsigned(RotateLeft(a,s),b)};function ConvertToWordArray(a){var b;var c=a.length;var d=c+8;var e=(d-(d%64))/64;var f=(e+1)*16;var g=Array(f-1);var h=0;var i=0;while(i<c){b=(i-(i%4))/4;h=(i%4)*8;g[b]=(g[b]|(a.charCodeAt(i)<<h));i++}b=(i-(i%4))/4;h=(i%4)*8;g[b]=g[b]|(0x80<<h);g[f-2]=c<<3;g[f-1]=c>>>29;return g};function WordToHex(a){var b="",WordToHexValue_temp="",lByte,lCount;for(lCount=0;lCount<=3;lCount++){lByte=(a>>>(lCount*8))&255;WordToHexValue_temp="0"+lByte.toString(16);b=b+WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2)}return b};function Utf8Encode(a){a=a.replace(/\r\n/g,"\n");var b="";for(var n=0;n<a.length;n++){var c=a.charCodeAt(n);if(c<128){b+=String.fromCharCode(c)}else if((c>127)&&(c<2048)){b+=String.fromCharCode((c>>6)|192);b+=String.fromCharCode((c&63)|128)}else{b+=String.fromCharCode((c>>12)|224);b+=String.fromCharCode(((c>>6)&63)|128);b+=String.fromCharCode((c&63)|128)}}return b};var x=Array();var k,AA,BB,CC,DD,a,b,c,d;var l=7,S12=12,S13=17,S14=22;var m=5,S22=9,S23=14,S24=20;var o=4,S32=11,S33=16,S34=23;var p=6,S42=10,S43=15,S44=21;j=Utf8Encode(j);x=ConvertToWordArray(j);a=0x67452301;b=0xEFCDAB89;c=0x98BADCFE;d=0x10325476;for(k=0;k<x.length;k+=16){AA=a;BB=b;CC=c;DD=d;a=FF(a,b,c,d,x[k+0],l,0xD76AA478);d=FF(d,a,b,c,x[k+1],S12,0xE8C7B756);c=FF(c,d,a,b,x[k+2],S13,0x242070DB);b=FF(b,c,d,a,x[k+3],S14,0xC1BDCEEE);a=FF(a,b,c,d,x[k+4],l,0xF57C0FAF);d=FF(d,a,b,c,x[k+5],S12,0x4787C62A);c=FF(c,d,a,b,x[k+6],S13,0xA8304613);b=FF(b,c,d,a,x[k+7],S14,0xFD469501);a=FF(a,b,c,d,x[k+8],l,0x698098D8);d=FF(d,a,b,c,x[k+9],S12,0x8B44F7AF);c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);a=FF(a,b,c,d,x[k+12],l,0x6B901122);d=FF(d,a,b,c,x[k+13],S12,0xFD987193);c=FF(c,d,a,b,x[k+14],S13,0xA679438E);b=FF(b,c,d,a,x[k+15],S14,0x49B40821);a=GG(a,b,c,d,x[k+1],m,0xF61E2562);d=GG(d,a,b,c,x[k+6],S22,0xC040B340);c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);b=GG(b,c,d,a,x[k+0],S24,0xE9B6C7AA);a=GG(a,b,c,d,x[k+5],m,0xD62F105D);d=GG(d,a,b,c,x[k+10],S22,0x2441453);c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);b=GG(b,c,d,a,x[k+4],S24,0xE7D3FBC8);a=GG(a,b,c,d,x[k+9],m,0x21E1CDE6);d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);c=GG(c,d,a,b,x[k+3],S23,0xF4D50D87);b=GG(b,c,d,a,x[k+8],S24,0x455A14ED);a=GG(a,b,c,d,x[k+13],m,0xA9E3E905);d=GG(d,a,b,c,x[k+2],S22,0xFCEFA3F8);c=GG(c,d,a,b,x[k+7],S23,0x676F02D9);b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);a=HH(a,b,c,d,x[k+5],o,0xFFFA3942);d=HH(d,a,b,c,x[k+8],S32,0x8771F681);c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);a=HH(a,b,c,d,x[k+1],o,0xA4BEEA44);d=HH(d,a,b,c,x[k+4],S32,0x4BDECFA9);c=HH(c,d,a,b,x[k+7],S33,0xF6BB4B60);b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);a=HH(a,b,c,d,x[k+13],o,0x289B7EC6);d=HH(d,a,b,c,x[k+0],S32,0xEAA127FA);c=HH(c,d,a,b,x[k+3],S33,0xD4EF3085);b=HH(b,c,d,a,x[k+6],S34,0x4881D05);a=HH(a,b,c,d,x[k+9],o,0xD9D4D039);d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);b=HH(b,c,d,a,x[k+2],S34,0xC4AC5665);a=II(a,b,c,d,x[k+0],p,0xF4292244);d=II(d,a,b,c,x[k+7],S42,0x432AFF97);c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);b=II(b,c,d,a,x[k+5],S44,0xFC93A039);a=II(a,b,c,d,x[k+12],p,0x655B59C3);d=II(d,a,b,c,x[k+3],S42,0x8F0CCC92);c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);b=II(b,c,d,a,x[k+1],S44,0x85845DD1);a=II(a,b,c,d,x[k+8],p,0x6FA87E4F);d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);c=II(c,d,a,b,x[k+6],S43,0xA3014314);b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);a=II(a,b,c,d,x[k+4],p,0xF7537E82);d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);c=II(c,d,a,b,x[k+2],S43,0x2AD7D2BB);b=II(b,c,d,a,x[k+9],S44,0xEB86D391);a=AddUnsigned(a,AA);b=AddUnsigned(b,BB);c=AddUnsigned(c,CC);d=AddUnsigned(d,DD)}var q=WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);return q.toLowerCase()}; | ||||
| 
 | ||||
							
								
								
									
										8
									
								
								lsp/placeholder.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lsp/placeholder.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
|          /* | ||||
|          * Placeholder plugin for jQuery | ||||
|          * --- | ||||
|          * Copyright 2010, Daniel Stocks (http://webcloud.se)
 | ||||
|          * Released under the MIT, BSD, and GPL Licenses. | ||||
|          */ | ||||
|          (function(b){function d(a){this.input=a;a.attr("type")=="password"&&this.handlePassword();b(a[0].form).submit(function(){if(a.hasClass("placeholder")&&a[0].value==a.attr("placeholder"))a[0].value=""})}d.prototype={show:function(a){if(this.input[0].value===""||a&&this.valueIsPlaceholder()){if(this.isPassword)try{this.input[0].setAttribute("type","text")}catch(b){this.input.before(this.fakePassword.show()).hide()}this.input.addClass("placeholder");this.input[0].value=this.input.attr("placeholder")}},hide:function(){if(this.valueIsPlaceholder()&&this.input.hasClass("placeholder")&&(this.input.removeClass("placeholder"),this.input[0].value="",this.isPassword)){try{this.input[0].setAttribute("type","password")}catch(a){}this.input.show();this.input[0].focus()}},valueIsPlaceholder:function(){return this.input[0].value==this.input.attr("placeholder")},handlePassword:function(){var a=this.input;a.attr("realType","password");this.isPassword=!0;if(b.browser.msie&&a[0].outerHTML){var c=b(a[0].outerHTML.replace(/type=(['"])?password\1/gi,"type=$1text$1"));this.fakePassword=c.val(a.attr("placeholder")).addClass("placeholder").focus(function(){a.trigger("focus");b(this).hide()});b(a[0].form).submit(function(){c.remove();a.show()})}}};var e=!!("placeholder"in document.createElement("input"));b.fn.placeholder=function(){return e?this:this.each(function(){var a=b(this),c=new d(a);c.show(!0);a.focus(function(){c.hide()});a.blur(function(){c.show(!1)});b.browser.msie&&(b(window).load(function(){a.val()&&a.removeClass("placeholder");c.show(!0)}),a.focus(function(){if(this.value==""){var a=this.createTextRange();a.collapse(!0);a.moveStart("character",0);a.select()}}))})}})(jQuery); | ||||
| 
 | ||||
							
								
								
									
										49
									
								
								lsp/server.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								lsp/server.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| <!doctype html> | ||||
| 
 | ||||
| <html lang='en'> | ||||
| 
 | ||||
|    <head> | ||||
| 
 | ||||
|       <meta charset='utf-8' /> | ||||
| 
 | ||||
|       <title>Mistserver Manager - not connected</title> | ||||
| 
 | ||||
|       <script src='jquery.js'></script> | ||||
|       <script src='placeholder.js'></script>  | ||||
|       <script src='md5.js'></script> | ||||
|       <script src='main.js'></script> | ||||
|       <script src='functions.js'></script> | ||||
| 
 | ||||
|       <link rel='stylesheet' href='style.css' /> | ||||
| 
 | ||||
|    </head> | ||||
| 
 | ||||
|    <body> | ||||
| 
 | ||||
|       <div id='header'> | ||||
| 
 | ||||
|          <div id='header-title'> | ||||
|             <span>Mistserver Manager</span> | ||||
|          </div> | ||||
| 
 | ||||
|          <div id='header-status'> | ||||
|             <span id='header-connection' class='disconnected'>Disconnected</span> | ||||
|             <span id='header-host'></span> | ||||
|          </div> | ||||
| 
 | ||||
|       </div> | ||||
| 
 | ||||
|       <ul id='nav'> | ||||
|          <li class='selected'>overview</li> | ||||
|          <li>protocols</li> | ||||
|          <li>streams</li> | ||||
|          <li>limits</li> | ||||
|          <li>logs</li> | ||||
|          <li id='logoutbutton'>disconnect</li> | ||||
|       </ul> | ||||
| 
 | ||||
|       <div id='page'></div> | ||||
| 
 | ||||
|    </body> | ||||
| 
 | ||||
| </html> | ||||
							
								
								
									
										375
									
								
								lsp/style.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								lsp/style.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,375 @@ | |||
| 
 | ||||
| 
 | ||||
| body | ||||
| { | ||||
|    background-color: #fafafa; | ||||
|    margin: 0; | ||||
| } | ||||
| 
 | ||||
| #page | ||||
| { | ||||
|    overflow: hidden; | ||||
|    margin: 10px -170px 0 230px; | ||||
|    padding: 0;    | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| .floatright | ||||
| { | ||||
|    float: right; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* content - tables */ | ||||
| 
 | ||||
| table | ||||
| { | ||||
|    width: 100%; | ||||
| } | ||||
| 
 | ||||
| table | ||||
| { | ||||
|    border-spacing: 0 4px; | ||||
| } | ||||
| 
 | ||||
| table thead | ||||
| { | ||||
|    background-color: #c8c8c8; | ||||
| } | ||||
| 
 | ||||
| table th, table td | ||||
| { | ||||
|    height: 30px; | ||||
|    padding: 0 0 0 30px; | ||||
| } | ||||
| 
 | ||||
| table th | ||||
| { | ||||
|    color: #505050; | ||||
|    text-align: left; | ||||
| } | ||||
| 
 | ||||
| table td | ||||
| { | ||||
|    color: #505050; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| tbody tr:nth-child(even) | ||||
| { | ||||
|    background-color: #f0f0f0; | ||||
| } | ||||
| tbody tr:nth-child(odd) | ||||
| { | ||||
|    background-color: #f3f3f3; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* login stuff */ | ||||
| 
 | ||||
| #login | ||||
| { | ||||
|    width: 250px; | ||||
| } | ||||
| 
 | ||||
| #login > input | ||||
| { | ||||
|    display: block; | ||||
|    margin: 5px 0 13px 0; | ||||
|    width: 240px; | ||||
| } | ||||
| 
 | ||||
| /* connect button */ | ||||
| 
 | ||||
| #login > button | ||||
| { | ||||
|    float: right; | ||||
|    margin: 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* input general */ | ||||
| input, select | ||||
| { | ||||
|    padding: 5px; | ||||
|    color: #505050; | ||||
|    border: 1px solid #b4b4b4; | ||||
| } | ||||
| 
 | ||||
| button | ||||
| { | ||||
|    height: 30px; | ||||
|    background-color: #505050; | ||||
|    color: #fff; | ||||
|    border: 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| tbody button, | ||||
| tbody select, | ||||
| tbody input | ||||
| { | ||||
|    height: 22px; | ||||
|    padding: 2px; | ||||
| } | ||||
| 
 | ||||
| tbody td button | ||||
| { | ||||
|    text-transform: uppercase; | ||||
|    font-weight: bold; | ||||
|    padding: 2px 7px 2px 7px; | ||||
| } | ||||
| 
 | ||||
| tbody td.center | ||||
| { | ||||
|    text-align: center; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #page > button | ||||
| { | ||||
|    margin: 12px 0 6px 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* header */ | ||||
| 
 | ||||
| #header | ||||
| { | ||||
|    margin: 30px 0 0 0; | ||||
|    width: 100%; | ||||
|    background-color: #b4b4b4; | ||||
|    height: 30px; | ||||
| } | ||||
| 
 | ||||
| #header-title | ||||
| { | ||||
|    padding: 0 0 0 30px; | ||||
|    float: left; | ||||
| } | ||||
| 
 | ||||
| #header-status | ||||
| { | ||||
|    float: right; | ||||
|    padding: 0 30px 0 0; | ||||
| } | ||||
| 
 | ||||
| #header-title, #header-status | ||||
| { | ||||
|    line-height: 30px; | ||||
| } | ||||
| 
 | ||||
| .disconnected, .red | ||||
| { | ||||
|    color: #cc3333; | ||||
| } | ||||
| 
 | ||||
| .connected, .green | ||||
| { | ||||
|    color: #14991a; | ||||
| } | ||||
| 
 | ||||
| .loggingin | ||||
| { | ||||
|    color: #ee8833; | ||||
| } | ||||
| 
 | ||||
| #header | ||||
| { | ||||
|    color: #fafafa; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* navigation */ | ||||
| 
 | ||||
| #nav | ||||
| { | ||||
|    float: left; | ||||
|    width: 200px; | ||||
|    list-style: none; | ||||
|    padding: 0; | ||||
|    margin: 10px 0 0 0; | ||||
| } | ||||
| 
 | ||||
| #nav li | ||||
| { | ||||
|    display: block; | ||||
|    color: #b4b4b4; | ||||
|    line-height: 30px; | ||||
|    padding: 0 0 0 30px; | ||||
|    margin: 5px 0 5px 0; | ||||
|    cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| #nav li:hover, #nav .selected | ||||
| { | ||||
|    color: #505050; | ||||
|    background-color: #c8c8c8; | ||||
| } | ||||
| 
 | ||||
| li#logoutbutton | ||||
| { | ||||
|    color: #cc3333; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| p, label | ||||
| { | ||||
|    color: #505050; | ||||
| } | ||||
| 
 | ||||
| p | ||||
| { | ||||
|    margin-top: 8px; | ||||
| } | ||||
| 
 | ||||
| label | ||||
| { | ||||
|    display: block; | ||||
|    margin: 6px 0 9px 0; | ||||
|    padding: 8px 0 0 0; | ||||
|    width: 400px; | ||||
| } | ||||
| 
 | ||||
| label input | ||||
| { | ||||
|    float: right; | ||||
|    margin: -8px 0 0 0; | ||||
|    width: 225px; | ||||
| } | ||||
| 
 | ||||
| label span | ||||
| { | ||||
|    float: right; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #editserver | ||||
| { | ||||
|    width: 400px; | ||||
| 
 | ||||
|    float: left; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| thead th .theadinfo | ||||
| { | ||||
|    color: #848484; | ||||
|    padding: 0 0 0 10px; | ||||
|    font: normal normal 9pt Arial, sans-serif; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* fonts */ | ||||
| 
 | ||||
| #header-title > span, #header-connection, #header-host, | ||||
| #nav, | ||||
| th, | ||||
| #login > button, | ||||
| p, | ||||
| label, | ||||
| #page label input, | ||||
| #page > button, | ||||
| #editserver > button, #forcesave > button | ||||
| { | ||||
|    font: normal bold 11pt Arial, sans-serif; | ||||
|    text-transform: uppercase; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| .nocapitals | ||||
| { | ||||
|    text-transform: none ; | ||||
| } | ||||
| 
 | ||||
| #editserver label input | ||||
| { | ||||
|    text-transform: none; | ||||
|    font-weight: normal; | ||||
| } | ||||
| 
 | ||||
| #login > input | ||||
| { | ||||
|    font: normal bold 11pt Arial, sans-serif; | ||||
| } | ||||
| 
 | ||||
| td | ||||
| { | ||||
|    font: normal normal 10pt Arial, sans-serif; | ||||
| } | ||||
| 
 | ||||
| #streams-filter | ||||
| { | ||||
|    height: 30px; | ||||
|    margin: 5px 0 0 0; | ||||
| 
 | ||||
|    text-align: right; | ||||
|    line-height: 30px; | ||||
| } | ||||
| 
 | ||||
| #streams-filter label | ||||
| { | ||||
|    margin: 0 15px 0 25px; | ||||
|    padding: 0; | ||||
|    display: inline-block; | ||||
|    width: auto; | ||||
| } | ||||
| 
 | ||||
| #streams-filter input | ||||
| { | ||||
|    float: none; | ||||
|    margin: 0 0 0 10px; | ||||
|    width: auto; | ||||
|    padding: 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #forcesave | ||||
| { | ||||
|    width: 400px; | ||||
|    float: left; | ||||
|    margin: 0 0 0 100px; | ||||
| } | ||||
| 
 | ||||
| #forcesave button | ||||
| { | ||||
|    float: right; | ||||
| } | ||||
| 
 | ||||
| #forcesave p | ||||
| { | ||||
|    text-transform: none; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #shield | ||||
| { | ||||
|    position: absolute; | ||||
|    background-color: #fff; | ||||
|    background-color: rgba(255, 255, 255, 0.5); | ||||
|    left: 0; | ||||
|    top: 60px; | ||||
|    z-index: 5; | ||||
| 
 | ||||
|    width: 100%; | ||||
|    height: 100%; | ||||
| 
 | ||||
|    color: #505050; | ||||
|    font: normal bold 11pt Arial, sans-serif; | ||||
|    text-align: center; | ||||
|    padding: 50px 0 0 0; | ||||
| } | ||||
| 
 | ||||
|        | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Niels Groot Obbink
						Niels Groot Obbink