home *** CD-ROM | disk | FTP | other *** search
/ PC World 2006 September / PCWorld_2006-09_cd.bin / audio-video / vlc / vlc-0.8.5-win32.exe / http / js / functions.js next >
Text File  |  2006-05-06  |  37KB  |  1,053 lines

  1. /*****************************************************************************
  2.  * functions.js: VLC media player web interface
  3.  *****************************************************************************
  4.  * Copyright (C) 2005-2006 the VideoLAN team
  5.  * $Id: functions.js 15238 2006-04-15 16:00:45Z dionoea $
  6.  *
  7.  * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /**********************************************************************
  25.  * Global variables
  26.  *********************************************************************/
  27.  
  28. var old_time = 0;
  29. var pl_cur_id;
  30.  
  31. /**********************************************************************
  32.  * Slider functions
  33.  *********************************************************************/
  34.  
  35. var slider_mouse_down = 0;
  36. var slider_dx = 0;
  37.  
  38. /* findPosX() from http://www.quirksmode.rg/js/indpos.html */
  39. function findPosX(obj)
  40. {
  41.     var curleft = 0;
  42.     if (obj.offsetParent)
  43.     {
  44.         while (obj.offsetParent)
  45.         {
  46.             curleft += obj.offsetLeft
  47.             obj = obj.offsetParent;
  48.         }
  49.     }
  50.     else if (obj.x)
  51.         curleft += obj.x;
  52.     return curleft;
  53. }
  54.  
  55. function slider_seek( e, bar )
  56. {
  57.     seek(Math.floor(( e.clientX + document.body.scrollLeft - findPosX( bar )) / 4)+"%25");
  58. }
  59. function slider_down( e, point )
  60. {
  61.     slider_mouse_down = 1;
  62.     slider_dx = e.clientX - findPosX( point );
  63. }
  64. function slider_up( e, bar )
  65. {
  66.     slider_mouse_down = 0;
  67.     /* slider_seek( e, bar ); */
  68. }
  69. function slider_move( e, bar )
  70. {
  71.     if( slider_mouse_down == 1 )
  72.     {
  73.         var slider_position  = Math.floor( e.clientX - slider_dx + document.body.scrollLeft - findPosX( bar ));
  74.         document.getElementById( 'main_slider_point' ).style.left = slider_position+"px";
  75.         slider_seek( e, bar );
  76.     }
  77. }
  78.  
  79. /**********************************************************************
  80.  * Misc utils
  81.  *********************************************************************/
  82.  
  83. /* XMLHttpRequest wrapper */
  84. function loadXMLDoc( url, callback )
  85. {
  86.   // branch for native XMLHttpRequest object
  87.   if ( window.XMLHttpRequest )
  88.   {
  89.     req = new XMLHttpRequest();
  90.     req.onreadystatechange = callback;
  91.     req.open( "GET", url, true );
  92.     req.send( null );
  93.   // branch for IE/Windows ActiveX version
  94.   }
  95.   else if ( window.ActiveXObject )
  96.   {
  97.     req = new ActiveXObject( "Microsoft.XMLHTTP" );
  98.     if ( req )
  99.     {
  100.       req.onreadystatechange = callback;
  101.       req.open( "GET", url, true );
  102.       req.send();
  103.     }
  104.   }
  105. }
  106.  
  107. /* fomat time in second as hh:mm:ss */
  108. function format_time( s )
  109. {
  110.     var hours = Math.floor(s/3600);
  111.     var minutes = Math.floor((s/60)%60);
  112.     var seconds = Math.floor(s%60);
  113.     if( hours < 10 ) hours = "0"+hours;
  114.     if( minutes < 10 ) minutes = "0"+minutes;
  115.     if( seconds < 10 ) seconds = "0"+seconds;
  116.     return hours+":"+minutes+":"+seconds;
  117. }
  118.  
  119. /* delete all a tag's children and add a text child node */
  120. function set_text( id, val )
  121. {
  122.     var elt = document.getElementById( id );
  123.     while( elt.hasChildNodes() )
  124.         elt.removeChild( elt.firstChild );
  125.     elt.appendChild( document.createTextNode( val ) );
  126. }
  127.  
  128. /* set item's 'element' attribute to value */
  129. function set_css( item, element, value )
  130. {
  131.     for( var j = 0; j < document.styleSheets.length; j++ )
  132.     {
  133.         var cssRules = document.styleSheets[j].cssRules;
  134.         if( !cssRules ) cssRules = document.styleSheets[j].rules;
  135.         for( var i = 0; i < cssRules.length; i++)
  136.         {
  137.             if( cssRules[i].selectorText == item )
  138.             {
  139.                 if( cssRules[i].style.setProperty )
  140.                     cssRules[i].style.setProperty( element, value, null );
  141.                 else
  142.                     cssRules[i].style.setAttribute( toCamelCase( element ), value );
  143.                 return;
  144.             }
  145.         }
  146.     }
  147. }
  148.  
  149. /* get item's 'element' attribute */
  150. function get_css( item, element )
  151. {
  152.     for( var j = 0; j < document.styleSheets.length; j++ )
  153.     {
  154.         var cssRules = document.styleSheets[j].cssRules;
  155.         if( !cssRules ) cssRules = document.styleSheets[j].rules;
  156.         for( var i = 0; i < cssRules.length; i++)
  157.         {
  158.             if( cssRules[i].selectorText == item )
  159.             {
  160.                 if( cssRules[i].style.getPropertyValue )
  161.                     return cssRules[i].style.getPropertyValue( element );
  162.                 else
  163.                     return cssRules[i].style.getAttribute( toCamelCase( element ) );
  164.             }
  165.         }
  166.     }
  167. }
  168.  
  169. function toggle_show( id )
  170. {
  171.     var element = document.getElementById( id );
  172.     if( element.style.display == 'block' || element.style.display == '' )
  173.     {
  174.         element.style.display = 'none';
  175.     }
  176.     else
  177.     {
  178.         element.style.display = 'block';
  179.     }
  180. }
  181. function toggle_show_node( id )
  182. {
  183.     var element = document.getElementById( 'pl_'+id );
  184.     var img = document.getElementById( 'pl_img_'+id );
  185.     if( element.style.display == 'block' || element.style.display == '' )
  186.     {
  187.         element.style.display = 'none';
  188.         img.setAttribute( 'src', 'images/plus.png' );
  189.         img.setAttribute( 'alt', '[+]' );
  190.     }
  191.     else
  192.     {
  193.         element.style.display = 'block';
  194.         img.setAttribute( 'src', 'images/minus.png' );
  195.         img.setAttribute( 'alt', '[-]' );
  196.     }
  197. }
  198.  
  199. function show( id ){ document.getElementById( id ).style.display = 'block'; }
  200. function showinline( id ){ document.getElementById( id ).style.display = 'inline'; }
  201.  
  202. function hide( id ){ document.getElementById( id ).style.display = 'none'; }
  203.  
  204. function checked( id ){ return document.getElementById( id ).checked; }
  205.  
  206. function value( id ){ return document.getElementById( id ).value; }
  207.  
  208. function setclass( obj, value )
  209. {
  210.     obj.setAttribute( 'class', value ); /* Firefox */
  211.     obj.setAttribute( 'className', value ); /* IE */
  212. }
  213.  
  214. function radio_value( name )
  215. {
  216.     var radio = document.getElementsByName( name );
  217.     for( var i = 0; i < radio.length; i++ )
  218.     {
  219.         if( radio[i].checked )
  220.         {
  221.             return radio[i].value;
  222.         }
  223.     }
  224.     return "";
  225. }
  226.  
  227. function check_and_replace_int( id, val )
  228. {
  229.     var objRegExp = /^\d+$/;
  230.     if( value( id ) != ''
  231.         && ( !objRegExp.test( value( id ) )
  232.              || parseInt( value( id ) ) < 1 ) )
  233.         return document.getElementById( id ).value = val;
  234.     return document.getElementById( id ).value;
  235. }
  236.  
  237. function addslashes( str ){ return str.replace(/\'/g, '\\\''); }
  238. function escapebackslashes( str ){ return str.replace(/\\/g, '\\\\'); }
  239.  
  240. function toCamelCase( str )
  241. {
  242.     str = str.split( '-' );
  243.     var cml = str[0];
  244.     for( var i=1; i<str.length; i++)
  245.         cml += str[i].charAt(0).toUpperCase()+str[i].substring(1);
  246.     return cml;
  247. }
  248.  
  249. function disable( id ){ document.getElementById( id ).disabled = true; }
  250.  
  251. function enable( id ){ document.getElementById( id ).disabled = false; }
  252.  
  253. function button_over( element ){ element.style.border = "1px solid #000"; }
  254.  
  255. function button_out( element ){ element.style.border = "1px solid #fff"; }
  256. function button_out_menu( element ){ element.style.border = "1px solid transparent"; }
  257.  
  258. function show_menu( id ){ document.getElementById(id).style.display = 'block'; }
  259. function hide_menu( id ){ document.getElementById(id).style.display = 'none'; }
  260.  
  261. /* toggle show help under the buttons */
  262. function toggle_btn_text()
  263. {
  264.     if( get_css( '.btn_text', 'display' ) == 'none' )
  265.     {
  266.         set_css( '.btn_text', 'display', 'block' );
  267.     }
  268.     else
  269.     {
  270.         set_css( '.btn_text', 'display', 'none' );
  271.     }
  272. }
  273.  
  274. function clear_children( elt )
  275. {   
  276.     if( elt )
  277.         while( elt.hasChildNodes() )
  278.             elt.removeChild( elt.firstChild );
  279. }
  280.  
  281. /**********************************************************************
  282.  * Interface actions
  283.  *********************************************************************/
  284. /* input actions */
  285. function in_play()
  286. {
  287.     var input = value('input_mrl');
  288.     if( value('sout_mrl') != '' )
  289.         input += ' '+value('sout_mrl');
  290.     var url = 'requests/status.xml?command=in_play&input='+encodeURIComponent( addslashes(escapebackslashes(input)) );
  291.     loadXMLDoc( url, parse_status );
  292.     setTimeout( 'update_playlist()', 1000 );
  293. }
  294. function in_enqueue()
  295. {
  296.     var input = value('input_mrl');
  297.     if( value('sout_mrl') != '' )
  298.         input += ' '+value('sout_mrl');
  299.     var url = 'requests/status.xml?command=in_enqueue&input='+encodeURIComponent( addslashes(escapebackslashes(input)) );
  300.     loadXMLDoc( url, parse_status );
  301.     setTimeout( 'update_playlist()', 1000 );
  302. }
  303.  
  304. /* playlist actions */
  305. function pl_play( id )
  306. {
  307.     loadXMLDoc( 'requests/status.xml?command=pl_play&id='+id, parse_status );
  308.     pl_cur_id = id;
  309.     setTimeout( 'update_playlist()', 1000 );
  310. }
  311. function pl_pause()
  312. {
  313.     loadXMLDoc( 'requests/status.xml?command=pl_pause&id='+pl_cur_id, parse_status );
  314. }
  315. function pl_stop()
  316. {
  317.     loadXMLDoc( 'requests/status.xml?command=pl_stop', parse_status );
  318.     setTimeout( 'update_playlist()', 1000 );
  319. }
  320. function pl_next()
  321. {
  322.     loadXMLDoc( 'requests/status.xml?command=pl_next', parse_status );
  323.     setTimeout( 'update_playlist()', 1000 );
  324. }
  325. function pl_previous()
  326. {
  327.     loadXMLDoc( 'requests/status.xml?command=pl_previous', parse_status );
  328.     setTimeout( 'update_playlist()', 1000 );
  329. }
  330. function pl_delete( id )
  331. {
  332.     loadXMLDoc( 'requests/status.xml?command=pl_delete&id='+id, parse_status );
  333.     setTimeout( 'update_playlist()', 1000 );
  334. }
  335. function pl_empty()
  336. {
  337.     loadXMLDoc( 'requests/status.xml?command=pl_empty', parse_status );
  338.     setTimeout( 'update_playlist()', 1000 );
  339. }
  340. function pl_sort( sort, order )
  341. {
  342.     loadXMLDoc( 'requests/status.xml?command=pl_sort&id='+order+'&val='+sort, parse_status );
  343.     setTimeout( 'update_playlist()', 1000 );
  344. }
  345. function pl_shuffle()
  346. {
  347.     loadXMLDoc( 'requests/status.xml?command=pl_random', parse_status );
  348.     setTimeout( 'update_playlist()', 1000 );
  349. }
  350. function pl_loop()
  351. {
  352.     loadXMLDoc( 'requests/status.xml?command=pl_loop', parse_status );
  353. }
  354. function pl_repeat()
  355. {
  356.     loadXMLDoc( 'requests/status.xml?command=pl_repeat', parse_status );
  357. }
  358. function pl_sd( value )
  359. {
  360.     loadXMLDoc( 'requests/status.xml?command=pl_sd&val='+value, parse_status );
  361. }
  362.  
  363. /* misc actions */
  364. function volume_down()
  365. {
  366.     loadXMLDoc( 'requests/status.xml?command=volume&val=-20', parse_status );
  367. }
  368. function volume_up()
  369. {
  370.     loadXMLDoc( 'requests/status.xml?command=volume&val=%2B20', parse_status );
  371. }
  372. function seek( pos )
  373. {
  374.     loadXMLDoc( 'requests/status.xml?command=seek&val='+pos, parse_status );
  375. }
  376. function fullscreen()
  377. {
  378.     loadXMLDoc( 'requests/status.xml?command=fullscreen', parse_status );
  379. }
  380. function update_status()
  381. {
  382.     loadXMLDoc( 'requests/status.xml', parse_status );
  383. }
  384. function update_playlist()
  385. {
  386.     loadXMLDoc( 'requests/playlist.xml', parse_playlist );
  387. }
  388.  
  389. /**********************************************************************
  390.  * Parse xml replies to XMLHttpRequests
  391.  *********************************************************************/
  392. /* parse request/status.xml */
  393. function parse_status()
  394. {
  395.     if( req.readyState == 4 )
  396.     {
  397.         if( req.status == 200 )
  398.         {
  399.             var status = req.responseXML.documentElement;
  400.             var timetag = status.getElementsByTagName( 'time' );
  401.             if( timetag.length > 0 )
  402.             {
  403.                 var new_time = timetag[0].firstChild.data;
  404.             }
  405.             else
  406.             {
  407.                 new_time = old_time;
  408.             }
  409.             var lengthtag = status.getElementsByTagName( 'length' );
  410.             var length;
  411.             if( lengthtag.length > 0 )
  412.             {
  413.                 length = lengthtag[0].firstChild.data;
  414.             }
  415.             else
  416.             {
  417.                 length = 0;
  418.             }
  419.             var slider_position;
  420.             positiontag = status.getElementsByTagName( 'position' );
  421.             if( length < 100 && positiontag.length > 0 )
  422.             {
  423.                 slider_position = ( positiontag[0].firstChild.data * 4 ) + "px";
  424.             }
  425.             else if( length > 0 )
  426.             {
  427.                 /* this is more precise if length > 100 */
  428.                 slider_position = Math.floor( ( new_time * 400 ) / length ) + "px";
  429.             }
  430.             else
  431.             {
  432.                 slider_position = 0;
  433.             }
  434.             if( old_time > new_time )
  435.                 setTimeout('update_playlist()',50);
  436.             old_time = new_time;
  437.             set_text( 'time', format_time( new_time ) );
  438.             set_text( 'length', format_time( length ) );
  439.             if( status.getElementsByTagName( 'volume' ).length != 0 )
  440.                 set_text( 'volume', Math.floor(status.getElementsByTagName( 'volume' )[0].firstChild.data/5.12)+'%' );
  441.             var statetag = status.getElementsByTagName( 'state' );
  442.             if( statetag.length > 0 )
  443.             {
  444.                 set_text( 'state', statetag[0].firstChild.data );
  445.             }
  446.             else
  447.             {
  448.                 set_text( 'state', '(?)' );
  449.             }
  450.             if( slider_mouse_down == 0 )
  451.             {
  452.                 document.getElementById( 'main_slider_point' ).style.left = slider_position;
  453.             }
  454.             var statustag = status.getElementsByTagName( 'state' );
  455.             if( statustag.length > 0 ? statustag[0].firstChild.data == "playing" : 0 )
  456.             {
  457.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/pause.png' );
  458.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'alt', 'Pause' );
  459.                 document.getElementById( 'btn_pause' ).setAttribute( 'title', 'Pause' );
  460.             }
  461.             else
  462.             {
  463.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/play.png' );
  464.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'alt', 'Play' );
  465.                 document.getElementById( 'btn_pause' ).setAttribute( 'title', 'Play' );
  466.             }
  467.  
  468.             var randomtag = status.getElementsByTagName( 'random' );
  469.             if( randomtag.length > 0 ? randomtag[0].firstChild.data == "1" : 0)
  470.                 setclass( document.getElementById( 'btn_shuffle'), 'on' );
  471.             else
  472.                 setclass( document.getElementById( 'btn_shuffle'), 'off' );
  473.                
  474.             var looptag = status.getElementsByTagName( 'loop' );
  475.             if( looptag.length > 0 ? looptag[0].firstChild.data == "1" : 0)
  476.                 setclass( document.getElementById( 'btn_loop'), 'on' );
  477.             else
  478.                 setclass( document.getElementById( 'btn_loop'), 'off' );
  479.  
  480.             var repeattag = status.getElementsByTagName( 'repeat' );
  481.             if( repeattag.length > 0 ? repeattag[0].firstChild.data == "1" : 0 )
  482.                 setclass( document.getElementById( 'btn_repeat'), 'on' );
  483.             else
  484.                 setclass( document.getElementById( 'btn_repeat'), 'off' );
  485.  
  486.             var tree = document.createElement( "ul" );
  487.             var categories = status.getElementsByTagName( 'category' );
  488.             var i;
  489.             for( i = 0; i < categories.length; i++ )
  490.             {
  491.                 var item = document.createElement( "li" );
  492.                 item.appendChild( document.createTextNode( categories[i].getAttribute( 'name' ) ) );
  493.                 var subtree = document.createElement( "dl" );
  494.                 var infos = categories[i].getElementsByTagName( 'info' );
  495.                 var j;
  496.                 for( j = 0; j < infos.length; j++ )
  497.                 {
  498.                     var subitem = document.createElement( "dt" );
  499.                     subitem.appendChild( document.createTextNode( infos[j].getAttribute( 'name' ) ) );
  500.                     subtree.appendChild( subitem );
  501.                     if( infos[j].hasChildNodes() )
  502.                     {
  503.                         var subitem = document.createElement( "dd" );
  504.                         subitem.appendChild( document.createTextNode( infos[j].firstChild.data ) );
  505.                         subtree.appendChild( subitem );
  506.                     }
  507.                 }
  508.                 item.appendChild( subtree );
  509.                 tree.appendChild( item );
  510.             }
  511.             var infotree = document.getElementById('infotree' );
  512.             clear_children( infotree );
  513.             infotree.appendChild( tree );
  514.             
  515.         }
  516.         else
  517.         {
  518.             /*alert( 'Error! HTTP server replied: ' + req.status );*/
  519.         }
  520.     }
  521. }
  522.  
  523. /* parse playlist.xml */
  524. function parse_playlist()
  525. {
  526.     if( req.readyState == 4 )
  527.     {
  528.         if( req.status == 200 )
  529.         {
  530.             var answer = req.responseXML.documentElement;
  531.             var playtree = document.getElementById( 'playtree' );
  532.             var pos = document.createElement( "div" );
  533.             var pos_top = pos;
  534.             var elt = answer.firstChild;
  535.             
  536.             pl_cur_id = 0;  /* changed to the current id is there actually
  537.                              * is a current id */
  538.             while( elt )
  539.             {
  540.                 if( elt.nodeName == "node" )
  541.                 {
  542.                     if( pos.hasChildNodes() )
  543.                         pos.appendChild( document.createElement( "br" ) );
  544.                     var nda = document.createElement( 'a' );
  545.                     nda.setAttribute( 'href', 'javascript:toggle_show_node(\''+elt.getAttribute( 'id' )+'\');' );
  546.                     var ndai = document.createElement( 'img' );
  547.                     ndai.setAttribute( 'src', 'images/minus.png' );
  548.                     ndai.setAttribute( 'alt', '[-]' );
  549.                     ndai.setAttribute( 'id', 'pl_img_'+elt.getAttribute( 'id' ) );
  550.                     nda.appendChild( ndai );
  551.                     pos.appendChild( nda );
  552.                     pos.appendChild( document.createTextNode( ' ' + elt.getAttribute( 'name' ) ) );
  553.  
  554.                     if( elt.getAttribute( 'ro' ) == 'rw' )
  555.                     {
  556.                         pos.appendChild( document.createTextNode( ' ' ) );
  557.                         var del = document.createElement( "a" );
  558.                         del.setAttribute( 'href', 'javascript:pl_delete('+elt.getAttribute( 'id' )+')' );
  559.                             var delimg = document.createElement( "img" );
  560.                             delimg.setAttribute( 'src', 'images/delete_small.png' );
  561.                             delimg.setAttribute( 'alt', '(delete)' );
  562.                         del.appendChild( delimg );
  563.                         pos.appendChild( del );
  564.                     }
  565.  
  566.                     var nd = document.createElement( "div" );
  567.                     setclass( nd, 'pl_node' );
  568.                     nd.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
  569.                     pos.appendChild( nd );
  570.                 }
  571.                 else if( elt.nodeName == "leaf" )
  572.                 {
  573.                     if( pos.hasChildNodes() )
  574.                     pos.appendChild( document.createElement( "br" ) );
  575.                     var pl = document.createElement( "a" );
  576.                     setclass( pl, 'pl_leaf' );
  577.                     pl.setAttribute( 'href', 'javascript:pl_play('+elt.getAttribute( 'id' )+');' );
  578.                     pl.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
  579.                     if( elt.getAttribute( 'current' ) == 'current' )
  580.                     {
  581.                         pl.style.fontWeight = 'bold';
  582.                         var nowplaying = document.getElementById( 'nowplaying' );
  583.                         clear_children( nowplaying );
  584.                         nowplaying.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
  585.                         pl.appendChild( document.createTextNode( '* '));
  586.                         pl_cur_id = elt.getAttribute( 'id' );
  587.                     }
  588.                     pl.setAttribute( 'title', elt.getAttribute( 'uri' ));
  589.                     pl.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
  590.                     var duration = elt.getAttribute( 'duration' );
  591.                     if( duration > 0 )
  592.                         pl.appendChild( document.createTextNode( " (" + format_time( elt.getAttribute( 'duration' ) / 1000000 ) + ")" ) );
  593.                     pos.appendChild( pl );
  594.  
  595.                     if( elt.getAttribute( 'ro' ) == 'rw' )
  596.                     {
  597.                         pos.appendChild( document.createTextNode( ' ' ) );
  598.                         var del = document.createElement( "a" );
  599.                         del.setAttribute( 'href', 'javascript:pl_delete('+elt.getAttribute( 'id' )+')' );
  600.                             var delimg = document.createElement( "img" );
  601.                             delimg.setAttribute( 'src', 'images/delete_small.png' );
  602.                             delimg.setAttribute( 'alt', '(delete)' );
  603.                         del.appendChild( delimg );
  604.                         pos.appendChild( del );
  605.                     }
  606.                 }
  607.                 if( elt.firstChild )
  608.                 {
  609.                     elt = elt.firstChild;
  610.                     pos = pos.lastChild;
  611.                 }
  612.                 else if( elt.nextSibling )
  613.                 {
  614.                     elt = elt.nextSibling;
  615.                     pos = pos;
  616.                 }
  617.                 else
  618.                 {
  619.                     while( ! elt.parentNode.nextSibling )
  620.                     {
  621.                         elt = elt.parentNode;
  622.                         if( ! elt.parentNode ) break;
  623.                     }
  624.                     if( ! elt.parentNode ) break;
  625.                     elt = elt.parentNode.nextSibling;
  626.                     pos = pos.parentNode;
  627.                 }
  628.             }
  629.             clear_children( playtree );
  630.             playtree.appendChild( pos_top );
  631.         }
  632.         else
  633.         {
  634.             /*alert( 'Error! HTTP server replied: ' + req.status );*/
  635.         }
  636.     }
  637. }
  638.  
  639. /* parse browse.xml */
  640. function parse_browse_dir( )
  641. {
  642.     if( req.readyState == 4 )
  643.     {
  644.         if( req.status == 200 )
  645.         {
  646.             var answer = req.responseXML.documentElement;
  647.             if( !answer ) return;
  648.             var browser = document.getElementById( 'browser' );
  649.             var pos = document.createElement( "div" );
  650.             var elt = answer.firstChild;
  651.             while( elt )
  652.             {
  653.                 if( elt.nodeName == "element" )
  654.                 {
  655.                     var item = document.createElement( "a" );
  656.                     setclass( item, 'browser' );
  657.                     if( elt.getAttribute( 'type' ) == 'directory' )
  658.                     {
  659.                         item.setAttribute( 'href', 'javascript:browse_dir(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');');
  660.                     }
  661.                     else
  662.                     {
  663.                         item.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');' );
  664.                     }
  665.                     item.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
  666.                     pos.appendChild( item );
  667.                     if( elt.getAttribute( 'type' ) == 'directory' )
  668.                     {
  669.                         pos.appendChild( document.createTextNode( ' ' ) );
  670.                         var item = document.createElement( "a" );
  671.                         setclass( item, 'browser' );
  672.                         item.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');');
  673.                         item.appendChild( document.createTextNode( '(select)' ) );
  674.                         pos.appendChild( item );
  675.                     }
  676.                     pos.appendChild( document.createElement( "br" ) );
  677.                 }
  678.                 elt = elt.nextSibling;
  679.             }
  680.             clear_children( browser );
  681.             browser.appendChild( pos );
  682.         }
  683.         else
  684.         {
  685.             /*alert( 'Error! HTTP server replied: ' + req.status );*/
  686.         }
  687.     }
  688. }
  689.  
  690. /**********************************************************************
  691.  * Input dialog functions
  692.  *********************************************************************/
  693. function hide_input( )
  694. {
  695.     document.getElementById( 'input_file' ).style.display = 'none';
  696.     document.getElementById( 'input_disc' ).style.display = 'none';
  697.     document.getElementById( 'input_network' ).style.display = 'none';
  698.     document.getElementById( 'input_fake' ).style.display = 'none';
  699. }
  700.  
  701. /* update the input MRL using data from the input file helper */
  702. /* FIXME ... subs support */
  703. function update_input_file()
  704. {
  705.     var mrl = document.getElementById( 'input_mrl' );
  706.  
  707.     mrl.value = value( 'input_file_filename' );
  708. }
  709.  
  710. /* update the input MRL using data from the input disc helper */
  711. function update_input_disc()
  712. {
  713.     var mrl     = document.getElementById( 'input_mrl' );
  714.     var type    = radio_value( "input_disc_type" );
  715.     var device  = value( "input_disc_dev" );
  716.  
  717.     var title   = check_and_replace_int( 'input_disc_title', 0 );
  718.     var chapter = check_and_replace_int( 'input_disc_chapter', 0 );
  719.     var subs    = check_and_replace_int( 'input_disc_subtrack', '' );
  720.     var audio   = check_and_replace_int( 'input_disc_audiotrack', 0 );
  721.  
  722.     mrl.value = "";
  723.  
  724.     if( type == "dvd" )
  725.     {
  726.         mrl.value += "dvd://";
  727.     }
  728.     else if( type == "dvdsimple" )
  729.     {
  730.         mrl.value += "dvdsimple://";
  731.     }
  732.     else if( type == "vcd" )
  733.     {
  734.         mrl.value += "vcd://";
  735.     }
  736.     else if( type == "cdda" )
  737.     {
  738.         mrl.value += "cdda://";
  739.     }
  740.  
  741.     mrl.value += device;
  742.  
  743.     if( title )
  744.     {
  745.         mrl.value += "@"+title;
  746.         if( chapter && type != "cdda" )
  747.             mrl.value += ":"+chapter;
  748.     }
  749.  
  750.     if( type != "cdda" )
  751.     {
  752.         if( subs != '' )
  753.             mrl.value += " :sub-track="+subs;
  754.         if( audio != '' )
  755.             mrl.value += " :audio-track="+audio;
  756.     }
  757.  
  758. }
  759.  
  760. /* update the input MRL using data from the input network helper */
  761. function update_input_net()
  762. {
  763.     var mrl = document.getElementById( 'input_mrl' );
  764.     var type = radio_value( "input_net_type" );
  765.     
  766.     check_and_replace_int( 'input_net_udp_port', 1234 );
  767.     check_and_replace_int( 'input_net_udpmcast_port', 1234 );
  768.  
  769.     mrl.value = "";
  770.  
  771.     if( type == "udp" )
  772.     {
  773.         mrl.value += "udp://";
  774.         if( checked( 'input_net_udp_forceipv6' ) )
  775.             mrl.value += "[::]";
  776.         if( value( 'input_net_udp_port' ) )
  777.             mrl.value += ":"+value( 'input_net_udp_port' );
  778.     }
  779.     else if( type == "udpmcast" )
  780.     {
  781.         mrl.value += "udp://@"+value( 'input_net_udpmcast_address');
  782.         if( value( 'input_net_udpmcast_port' ) )
  783.             mrl.value += ":"+value( 'input_net_udpmcast_port' );
  784.     }
  785.     else if( type == "http" )
  786.     {
  787.         var url = value( 'input_net_http_url' );
  788.         if( url.substring(0,7) != "http://"
  789.             && url.substring(0,8) != "https://"
  790.             && url.substring(0,6) != "ftp://"
  791.             && url.substring(0,6) != "mms://"
  792.             && url.substring(0,7) != "mmsh://" )
  793.             mrl.value += "http://";
  794.         mrl.value += url;
  795.     }
  796.     else if( type == "rtsp" )
  797.     {
  798.         var url = value( 'input_net_rtsp_url' );
  799.         if( url.substring(0,7) != "rtsp://" )
  800.             mrl.value += "rtsp://";
  801.         mrl.value += url;
  802.     }
  803.  
  804.     if( checked( "input_net_timeshift" ) )
  805.         mrl.value += " :access-filter=timeshift";
  806. }
  807.  
  808. /* update the input MRL using data from the input fake helper */
  809. function update_input_fake()
  810. {
  811.     var mrl = document.getElementById( 'input_mrl' );
  812.  
  813.     mrl.value = "fake:";
  814.     mrl.value += " :fake-file=" + value( "input_fake_filename" );
  815.  
  816.     if( value( "input_fake_width" ) )
  817.         mrl.value += " :fake-width=" + value( "input_fake_width" );
  818.     if( value( "input_fake_height" ) )
  819.         mrl.value += " :fake-height=" + value( "input_fake_height" );
  820.     if( value( "input_fake_ar" ) )
  821.         mrl.value += " :fake-ar=" + value( "input_fake_ar" );
  822. }
  823.  
  824. /**********************************************************************
  825.  * Sout dialog functions
  826.  *********************************************************************/
  827. /* toggle show the full sout interface */
  828. function toggle_show_sout_helper()
  829. {
  830.     var element = document.getElementById( "sout_helper" );
  831.     if( element.style.display == 'block' )
  832.     {
  833.         element.style.display = 'none';
  834.         document.getElementById( "sout_helper_toggle" ).value = 'Full sout interface';
  835.     }
  836.     else
  837.     {
  838.         element.style.display = 'block';
  839.         document.getElementById( "sout_helper_toggle" ).value = 'Hide sout interface';
  840.     }
  841. }
  842.  
  843. /* update the sout MRL using data from the sout_helper */
  844. function update_sout()
  845. {
  846.     var mrl = document.getElementById( 'sout_mrl' );
  847.     mrl.value = "";
  848.  
  849.     check_and_replace_int( 'sout_http_port', 8080 );
  850.     check_and_replace_int( 'sout_mmsh_port', 8080 );
  851.     check_and_replace_int( 'sout_rtp_port', 1234 );
  852.     check_and_replace_int( 'sout_udp_port', 1234 );
  853.     check_and_replace_int( 'sout_ttl', 1 );
  854.  
  855.     if( checked( 'sout_soverlay' ) )
  856.     {
  857.         disable( 'sout_scodec' );
  858.         disable( 'sout_sub' );
  859.     }
  860.     else
  861.     {
  862.         enable( 'sout_scodec' );
  863.         enable( 'sout_sub' );
  864.     }
  865.  
  866.     var transcode =  checked( 'sout_vcodec_s' ) || checked( 'sout_acodec_s' )
  867.                   || checked( 'sout_sub' )      || checked( 'sout_soverlay' );
  868.  
  869.     if( transcode )
  870.     {
  871.         mrl.value += ":sout=#transcode{";
  872.         var alot = false; /* alot == at least one transcode */
  873.         if( checked( 'sout_vcodec_s' ) )
  874.         {
  875.             mrl.value += "vcodec="+value( 'sout_vcodec' )+",vb="+value( 'sout_vb' )+",scale="+value( 'sout_scale' );
  876.             alot = true;
  877.         }
  878.         if( checked( 'sout_acodec_s' ) )
  879.         {
  880.             if( alot ) mrl.value += ",";
  881.             mrl.value += "acodec="+value( 'sout_acodec' )+",ab="+value( 'sout_ab' );
  882.             if( value( 'sout_channels' ) )
  883.                 mrl.value += ",channels="+value( 'sout_channels' );
  884.             alot = true;
  885.         }
  886.         if( checked( 'sout_soverlay' ) )
  887.         {
  888.             if( alot ) mrl.value += ",";
  889.             mrl.value += "soverlay";
  890.             alot = true;
  891.         }
  892.         else if( checked( 'sout_sub' ) )
  893.         {
  894.             if( alot ) mrl.value += ",";
  895.             mrl.value += "scodec="+value( 'sout_scodec' );
  896.             alot = true;
  897.         }
  898.         mrl.value += value( 'sout_transcode_extra' );
  899.             
  900.         mrl.value += "}";
  901.     }
  902.  
  903.     var output = checked( 'sout_display' ) + checked( 'sout_file' )
  904.                + checked( 'sout_http' )    + checked( 'sout_mmsh' )
  905.                + checked( 'sout_rtp' )     + checked( 'sout_udp' );
  906.  
  907.     if( output )
  908.     {
  909.         if( transcode )
  910.             mrl.value += ":";
  911.         else
  912.             mrl.value += ":sout=#";
  913.         var aloo = false; /* aloo == at least one output */
  914.         var mux = radio_value( 'sout_mux' );
  915.         var ttl = parseInt( value( 'sout_ttl' ) );
  916.         if( output > 1 ) mrl.value += "duplicate{";
  917.         if( checked( 'sout_display' ) )
  918.         {
  919.             if( output > 1 ) mrl.value += "dst="
  920.             mrl.value += "display";
  921.             aloo = true;
  922.         }
  923.         if( checked( 'sout_file' ) )
  924.         {
  925.             if( aloo ) mrl.value += ",";
  926.             if( output > 1 ) mrl.value += "dst="
  927.             mrl.value += "std{access=file,mux="+mux+",dst="+value( 'sout_file_filename' )+"}";
  928.             aloo = true;
  929.         }
  930.         if( checked( 'sout_http' ) )
  931.         {
  932.             if( aloo ) mrl.value += ",";
  933.             if( output > 1 ) mrl.value += "dst="
  934.             mrl.value += "std{access=http,mux="+mux+",dst="+value( 'sout_http_addr' );
  935.             if( value( 'sout_http_port' ) )
  936.                 mrl.value += ":"+value( 'sout_http_port' );
  937.             mrl.value += "}";
  938.             aloo = true;
  939.         }
  940.         if( checked( 'sout_mmsh' ) )
  941.         {
  942.             if( aloo ) mrl.value += ",";
  943.             if( output > 1 ) mrl.value += "dst="
  944.             mrl.value += "std{access=mmsh,mux="+mux+",dst="+value( 'sout_mmsh_addr' );
  945.             if( value( 'sout_mmsh_port' ) )
  946.                 mrl.value += ":"+value( 'sout_mmsh_port' );
  947.             mrl.value += "}";
  948.             aloo = true;
  949.         }
  950.         if( checked( 'sout_rtp' ) )
  951.         {
  952.             if( aloo ) mrl.value += ",";
  953.             if( output > 1 ) mrl.value += "dst="
  954.             mrl.value += "std{access=rtp";
  955.             if( ttl ) mrl.value += "{ttl="+ttl+"}";
  956.             mrl.value += ",mux="+mux+",dst="+value( 'sout_rtp_addr' );
  957.             if( value( 'sout_rtp_port' ) )
  958.                 mrl.value += ":"+value( 'sout_rtp_port' );
  959.             if( checked( 'sout_sap' ) )
  960.             {
  961.                 mrl.value += ",sap";
  962.                 if( value( 'sout_sap_group' ) != '' )
  963.                 {
  964.                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
  965.                 }
  966.                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
  967.             }
  968.             mrl.value += "}";
  969.             aloo = true;
  970.         }
  971.         if( checked( 'sout_udp' ) )
  972.         {
  973.             if( aloo ) mrl.value += ",";
  974.             if( output > 1 ) mrl.value += "dst="
  975.             mrl.value += "std{access=udp";
  976.             if( ttl ) mrl.value += "{ttl="+ttl+"}";
  977.             mrl.value += ",mux="+mux+",dst="+value( 'sout_udp_addr' );
  978.             if( value('sout_udp_port' ) )
  979.                 mrl.value += ":"+value( 'sout_udp_port' );
  980.             if( checked( 'sout_sap' ) )
  981.             {
  982.                 mrl.value += ",sap";
  983.                 if( value( 'sout_sap_group' ) != '' )
  984.                 {
  985.                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
  986.                 }
  987.                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
  988.             }
  989.             mrl.value += "}";
  990.             aloo = true;
  991.         }
  992.         if( output > 1 ) mrl.value += "}";
  993.     }
  994.  
  995.     if( ( transcode || output ) && checked( 'sout_all' ) )
  996.         mrl.value += " :sout-all";
  997. }
  998.  
  999. /* reset sout mrl value */
  1000. function reset_sout()
  1001. {
  1002.     document.getElementById('sout_mrl').value = value('sout_old_mrl');
  1003. }
  1004.  
  1005. /* save sout mrl value */
  1006. function save_sout()
  1007. {
  1008.     document.getElementById('sout_old_mrl').value = value('sout_mrl');
  1009. }
  1010.  
  1011. /**********************************************************************
  1012.  * Browser dialog functions
  1013.  *********************************************************************/
  1014. /* only browse() should be called directly */
  1015. function browse( dest )
  1016. {
  1017.     document.getElementById( 'browse_dest' ).value = dest;
  1018.     document.getElementById( 'browse_lastdir' ).value;
  1019.     browse_dir( document.getElementById( 'browse_lastdir' ).value );
  1020.     show( 'browse' );
  1021. }
  1022. function browse_dir( dir )
  1023. {
  1024.     document.getElementById( 'browse_lastdir' ).value = dir;
  1025.     loadXMLDoc( 'requests/browse.xml?dir='+encodeURIComponent(dir), parse_browse_dir );
  1026. }
  1027. function browse_path( p )
  1028. {
  1029.     document.getElementById( value( 'browse_dest' ) ).value = p;
  1030.     hide( 'browse' );
  1031.     document.getElementById( value( 'browse_dest' ) ).focus();
  1032. }
  1033.  
  1034. /**********************************************************************
  1035.  * Periodically update stuff in the interface
  1036.  *********************************************************************/
  1037. function loop_refresh_status()
  1038. {
  1039.     setTimeout( 'loop_refresh_status()', 1000 );
  1040.     update_status();
  1041. }
  1042. function loop_refresh_playlist()
  1043. {
  1044.     /* setTimeout( 'loop_refresh_playlist()', 10000 ); */
  1045.     update_playlist();
  1046. }
  1047. function loop_refresh()
  1048. {
  1049.     setTimeout( 'loop_refresh_status()', 1 );
  1050.     setTimeout( 'loop_refresh_playlist()', 1 );
  1051. }
  1052.  
  1053.