home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 May / PCWorld_2007-05_cd.bin / temacd / vlc / vlc-0.8.6a-win32.exe / http / js / functions.js next >
Text File  |  2007-01-04  |  37KB  |  1,057 lines

  1. /*****************************************************************************
  2.  * functions.js: VLC media player web interface
  3.  *****************************************************************************
  4.  * Copyright (C) 2005-2006 the VideoLAN team
  5.  * $Id: functions.js 16460 2006-08-31 22:01:13Z hartman $
  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 snapshot()
  381. {
  382.     loadXMLDoc( 'requests/status.xml?command=snapshot', parse_status );
  383. }
  384. function update_status()
  385. {
  386.     loadXMLDoc( 'requests/status.xml', parse_status );
  387. }
  388. function update_playlist()
  389. {
  390.     loadXMLDoc( 'requests/playlist.xml', parse_playlist );
  391. }
  392.  
  393. /**********************************************************************
  394.  * Parse xml replies to XMLHttpRequests
  395.  *********************************************************************/
  396. /* parse request/status.xml */
  397. function parse_status()
  398. {
  399.     if( req.readyState == 4 )
  400.     {
  401.         if( req.status == 200 )
  402.         {
  403.             var status = req.responseXML.documentElement;
  404.             var timetag = status.getElementsByTagName( 'time' );
  405.             if( timetag.length > 0 )
  406.             {
  407.                 var new_time = timetag[0].firstChild.data;
  408.             }
  409.             else
  410.             {
  411.                 new_time = old_time;
  412.             }
  413.             var lengthtag = status.getElementsByTagName( 'length' );
  414.             var length;
  415.             if( lengthtag.length > 0 )
  416.             {
  417.                 length = lengthtag[0].firstChild.data;
  418.             }
  419.             else
  420.             {
  421.                 length = 0;
  422.             }
  423.             var slider_position;
  424.             positiontag = status.getElementsByTagName( 'position' );
  425.             if( length < 100 && positiontag.length > 0 )
  426.             {
  427.                 slider_position = ( positiontag[0].firstChild.data * 4 ) + "px";
  428.             }
  429.             else if( length > 0 )
  430.             {
  431.                 /* this is more precise if length > 100 */
  432.                 slider_position = Math.floor( ( new_time * 400 ) / length ) + "px";
  433.             }
  434.             else
  435.             {
  436.                 slider_position = 0;
  437.             }
  438.             if( old_time > new_time )
  439.                 setTimeout('update_playlist()',50);
  440.             old_time = new_time;
  441.             set_text( 'time', format_time( new_time ) );
  442.             set_text( 'length', format_time( length ) );
  443.             if( status.getElementsByTagName( 'volume' ).length != 0 )
  444.                 set_text( 'volume', Math.floor(status.getElementsByTagName( 'volume' )[0].firstChild.data/5.12)+'%' );
  445.             var statetag = status.getElementsByTagName( 'state' );
  446.             if( statetag.length > 0 )
  447.             {
  448.                 set_text( 'state', statetag[0].firstChild.data );
  449.             }
  450.             else
  451.             {
  452.                 set_text( 'state', '(?)' );
  453.             }
  454.             if( slider_mouse_down == 0 )
  455.             {
  456.                 document.getElementById( 'main_slider_point' ).style.left = slider_position;
  457.             }
  458.             var statustag = status.getElementsByTagName( 'state' );
  459.             if( statustag.length > 0 ? statustag[0].firstChild.data == "playing" : 0 )
  460.             {
  461.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/pause.png' );
  462.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'alt', 'Pause' );
  463.                 document.getElementById( 'btn_pause' ).setAttribute( 'title', 'Pause' );
  464.             }
  465.             else
  466.             {
  467.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/play.png' );
  468.                 document.getElementById( 'btn_pause_img' ).setAttribute( 'alt', 'Play' );
  469.                 document.getElementById( 'btn_pause' ).setAttribute( 'title', 'Play' );
  470.             }
  471.  
  472.             var randomtag = status.getElementsByTagName( 'random' );
  473.             if( randomtag.length > 0 ? randomtag[0].firstChild.data == "1" : 0)
  474.                 setclass( document.getElementById( 'btn_shuffle'), 'on' );
  475.             else
  476.                 setclass( document.getElementById( 'btn_shuffle'), 'off' );
  477.                
  478.             var looptag = status.getElementsByTagName( 'loop' );
  479.             if( looptag.length > 0 ? looptag[0].firstChild.data == "1" : 0)
  480.                 setclass( document.getElementById( 'btn_loop'), 'on' );
  481.             else
  482.                 setclass( document.getElementById( 'btn_loop'), 'off' );
  483.  
  484.             var repeattag = status.getElementsByTagName( 'repeat' );
  485.             if( repeattag.length > 0 ? repeattag[0].firstChild.data == "1" : 0 )
  486.                 setclass( document.getElementById( 'btn_repeat'), 'on' );
  487.             else
  488.                 setclass( document.getElementById( 'btn_repeat'), 'off' );
  489.  
  490.             var tree = document.createElement( "ul" );
  491.             var categories = status.getElementsByTagName( 'category' );
  492.             var i;
  493.             for( i = 0; i < categories.length; i++ )
  494.             {
  495.                 var item = document.createElement( "li" );
  496.                 item.appendChild( document.createTextNode( categories[i].getAttribute( 'name' ) ) );
  497.                 var subtree = document.createElement( "dl" );
  498.                 var infos = categories[i].getElementsByTagName( 'info' );
  499.                 var j;
  500.                 for( j = 0; j < infos.length; j++ )
  501.                 {
  502.                     var subitem = document.createElement( "dt" );
  503.                     subitem.appendChild( document.createTextNode( infos[j].getAttribute( 'name' ) ) );
  504.                     subtree.appendChild( subitem );
  505.                     if( infos[j].hasChildNodes() )
  506.                     {
  507.                         var subitem = document.createElement( "dd" );
  508.                         subitem.appendChild( document.createTextNode( infos[j].firstChild.data ) );
  509.                         subtree.appendChild( subitem );
  510.                     }
  511.                 }
  512.                 item.appendChild( subtree );
  513.                 tree.appendChild( item );
  514.             }
  515.             var infotree = document.getElementById('infotree' );
  516.             clear_children( infotree );
  517.             infotree.appendChild( tree );
  518.             
  519.         }
  520.         else
  521.         {
  522.             /*alert( 'Error! HTTP server replied: ' + req.status );*/
  523.         }
  524.     }
  525. }
  526.  
  527. /* parse playlist.xml */
  528. function parse_playlist()
  529. {
  530.     if( req.readyState == 4 )
  531.     {
  532.         if( req.status == 200 )
  533.         {
  534.             var answer = req.responseXML.documentElement;
  535.             var playtree = document.getElementById( 'playtree' );
  536.             var pos = document.createElement( "div" );
  537.             var pos_top = pos;
  538.             var elt = answer.firstChild;
  539.             
  540.             pl_cur_id = 0;  /* changed to the current id is there actually
  541.                              * is a current id */
  542.             while( elt )
  543.             {
  544.                 if( elt.nodeName == "node" )
  545.                 {
  546.                     if( pos.hasChildNodes() )
  547.                         pos.appendChild( document.createElement( "br" ) );
  548.                     var nda = document.createElement( 'a' );
  549.                     nda.setAttribute( 'href', 'javascript:toggle_show_node(\''+elt.getAttribute( 'id' )+'\');' );
  550.                     var ndai = document.createElement( 'img' );
  551.                     ndai.setAttribute( 'src', 'images/minus.png' );
  552.                     ndai.setAttribute( 'alt', '[-]' );
  553.                     ndai.setAttribute( 'id', 'pl_img_'+elt.getAttribute( 'id' ) );
  554.                     nda.appendChild( ndai );
  555.                     pos.appendChild( nda );
  556.                     pos.appendChild( document.createTextNode( ' ' + elt.getAttribute( 'name' ) ) );
  557.  
  558.                     if( elt.getAttribute( 'ro' ) == 'rw' )
  559.                     {
  560.                         pos.appendChild( document.createTextNode( ' ' ) );
  561.                         var del = document.createElement( "a" );
  562.                         del.setAttribute( 'href', 'javascript:pl_delete('+elt.getAttribute( 'id' )+')' );
  563.                             var delimg = document.createElement( "img" );
  564.                             delimg.setAttribute( 'src', 'images/delete_small.png' );
  565.                             delimg.setAttribute( 'alt', '(delete)' );
  566.                         del.appendChild( delimg );
  567.                         pos.appendChild( del );
  568.                     }
  569.  
  570.                     var nd = document.createElement( "div" );
  571.                     setclass( nd, 'pl_node' );
  572.                     nd.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
  573.                     pos.appendChild( nd );
  574.                 }
  575.                 else if( elt.nodeName == "leaf" )
  576.                 {
  577.                     if( pos.hasChildNodes() )
  578.                     pos.appendChild( document.createElement( "br" ) );
  579.                     var pl = document.createElement( "a" );
  580.                     setclass( pl, 'pl_leaf' );
  581.                     pl.setAttribute( 'href', 'javascript:pl_play('+elt.getAttribute( 'id' )+');' );
  582.                     pl.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
  583.                     if( elt.getAttribute( 'current' ) == 'current' )
  584.                     {
  585.                         pl.style.fontWeight = 'bold';
  586.                         var nowplaying = document.getElementById( 'nowplaying' );
  587.                         clear_children( nowplaying );
  588.                         nowplaying.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
  589.                         pl.appendChild( document.createTextNode( '* '));
  590.                         pl_cur_id = elt.getAttribute( 'id' );
  591.                     }
  592.                     pl.setAttribute( 'title', elt.getAttribute( 'uri' ));
  593.                     pl.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
  594.                     var duration = elt.getAttribute( 'duration' );
  595.                     if( duration > 0 )
  596.                         pl.appendChild( document.createTextNode( " (" + format_time( elt.getAttribute( 'duration' ) / 1000000 ) + ")" ) );
  597.                     pos.appendChild( pl );
  598.  
  599.                     if( elt.getAttribute( 'ro' ) == 'rw' )
  600.                     {
  601.                         pos.appendChild( document.createTextNode( ' ' ) );
  602.                         var del = document.createElement( "a" );
  603.                         del.setAttribute( 'href', 'javascript:pl_delete('+elt.getAttribute( 'id' )+')' );
  604.                             var delimg = document.createElement( "img" );
  605.                             delimg.setAttribute( 'src', 'images/delete_small.png' );
  606.                             delimg.setAttribute( 'alt', '(delete)' );
  607.                         del.appendChild( delimg );
  608.                         pos.appendChild( del );
  609.                     }
  610.                 }
  611.                 if( elt.firstChild )
  612.                 {
  613.                     elt = elt.firstChild;
  614.                     pos = pos.lastChild;
  615.                 }
  616.                 else if( elt.nextSibling )
  617.                 {
  618.                     elt = elt.nextSibling;
  619.                     pos = pos;
  620.                 }
  621.                 else
  622.                 {
  623.                     while( ! elt.parentNode.nextSibling )
  624.                     {
  625.                         elt = elt.parentNode;
  626.                         if( ! elt.parentNode ) break;
  627.                     }
  628.                     if( ! elt.parentNode ) break;
  629.                     elt = elt.parentNode.nextSibling;
  630.                     pos = pos.parentNode;
  631.                 }
  632.             }
  633.             clear_children( playtree );
  634.             playtree.appendChild( pos_top );
  635.         }
  636.         else
  637.         {
  638.             /*alert( 'Error! HTTP server replied: ' + req.status );*/
  639.         }
  640.     }
  641. }
  642.  
  643. /* parse browse.xml */
  644. function parse_browse_dir( )
  645. {
  646.     if( req.readyState == 4 )
  647.     {
  648.         if( req.status == 200 )
  649.         {
  650.             var answer = req.responseXML.documentElement;
  651.             if( !answer ) return;
  652.             var browser = document.getElementById( 'browser' );
  653.             var pos = document.createElement( "div" );
  654.             var elt = answer.firstChild;
  655.             while( elt )
  656.             {
  657.                 if( elt.nodeName == "element" )
  658.                 {
  659.                     var item = document.createElement( "a" );
  660.                     setclass( item, 'browser' );
  661.                     if( elt.getAttribute( 'type' ) == 'directory' )
  662.                     {
  663.                         item.setAttribute( 'href', 'javascript:browse_dir(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');');
  664.                     }
  665.                     else
  666.                     {
  667.                         item.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');' );
  668.                     }
  669.                     item.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
  670.                     pos.appendChild( item );
  671.                     if( elt.getAttribute( 'type' ) == 'directory' )
  672.                     {
  673.                         pos.appendChild( document.createTextNode( ' ' ) );
  674.                         var item = document.createElement( "a" );
  675.                         setclass( item, 'browser' );
  676.                         item.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');');
  677.                         item.appendChild( document.createTextNode( '(select)' ) );
  678.                         pos.appendChild( item );
  679.                     }
  680.                     pos.appendChild( document.createElement( "br" ) );
  681.                 }
  682.                 elt = elt.nextSibling;
  683.             }
  684.             clear_children( browser );
  685.             browser.appendChild( pos );
  686.         }
  687.         else
  688.         {
  689.             /*alert( 'Error! HTTP server replied: ' + req.status );*/
  690.         }
  691.     }
  692. }
  693.  
  694. /**********************************************************************
  695.  * Input dialog functions
  696.  *********************************************************************/
  697. function hide_input( )
  698. {
  699.     document.getElementById( 'input_file' ).style.display = 'none';
  700.     document.getElementById( 'input_disc' ).style.display = 'none';
  701.     document.getElementById( 'input_network' ).style.display = 'none';
  702.     document.getElementById( 'input_fake' ).style.display = 'none';
  703. }
  704.  
  705. /* update the input MRL using data from the input file helper */
  706. /* FIXME ... subs support */
  707. function update_input_file()
  708. {
  709.     var mrl = document.getElementById( 'input_mrl' );
  710.  
  711.     mrl.value = value( 'input_file_filename' );
  712. }
  713.  
  714. /* update the input MRL using data from the input disc helper */
  715. function update_input_disc()
  716. {
  717.     var mrl     = document.getElementById( 'input_mrl' );
  718.     var type    = radio_value( "input_disc_type" );
  719.     var device  = value( "input_disc_dev" );
  720.  
  721.     var title   = check_and_replace_int( 'input_disc_title', 0 );
  722.     var chapter = check_and_replace_int( 'input_disc_chapter', 0 );
  723.     var subs    = check_and_replace_int( 'input_disc_subtrack', '' );
  724.     var audio   = check_and_replace_int( 'input_disc_audiotrack', 0 );
  725.  
  726.     mrl.value = "";
  727.  
  728.     if( type == "dvd" )
  729.     {
  730.         mrl.value += "dvd://";
  731.     }
  732.     else if( type == "dvdsimple" )
  733.     {
  734.         mrl.value += "dvdsimple://";
  735.     }
  736.     else if( type == "vcd" )
  737.     {
  738.         mrl.value += "vcd://";
  739.     }
  740.     else if( type == "cdda" )
  741.     {
  742.         mrl.value += "cdda://";
  743.     }
  744.  
  745.     mrl.value += device;
  746.  
  747.     if( title )
  748.     {
  749.         mrl.value += "@"+title;
  750.         if( chapter && type != "cdda" )
  751.             mrl.value += ":"+chapter;
  752.     }
  753.  
  754.     if( type != "cdda" )
  755.     {
  756.         if( subs != '' )
  757.             mrl.value += " :sub-track="+subs;
  758.         if( audio != '' )
  759.             mrl.value += " :audio-track="+audio;
  760.     }
  761.  
  762. }
  763.  
  764. /* update the input MRL using data from the input network helper */
  765. function update_input_net()
  766. {
  767.     var mrl = document.getElementById( 'input_mrl' );
  768.     var type = radio_value( "input_net_type" );
  769.     
  770.     check_and_replace_int( 'input_net_udp_port', 1234 );
  771.     check_and_replace_int( 'input_net_udpmcast_port', 1234 );
  772.  
  773.     mrl.value = "";
  774.  
  775.     if( type == "udp" )
  776.     {
  777.         mrl.value += "udp://";
  778.         if( checked( 'input_net_udp_forceipv6' ) )
  779.             mrl.value += "[::]";
  780.         if( value( 'input_net_udp_port' ) )
  781.             mrl.value += ":"+value( 'input_net_udp_port' );
  782.     }
  783.     else if( type == "udpmcast" )
  784.     {
  785.         mrl.value += "udp://@"+value( 'input_net_udpmcast_address');
  786.         if( value( 'input_net_udpmcast_port' ) )
  787.             mrl.value += ":"+value( 'input_net_udpmcast_port' );
  788.     }
  789.     else if( type == "http" )
  790.     {
  791.         var url = value( 'input_net_http_url' );
  792.         if( url.substring(0,7) != "http://"
  793.             && url.substring(0,8) != "https://"
  794.             && url.substring(0,6) != "ftp://"
  795.             && url.substring(0,6) != "mms://"
  796.             && url.substring(0,7) != "mmsh://" )
  797.             mrl.value += "http://";
  798.         mrl.value += url;
  799.     }
  800.     else if( type == "rtsp" )
  801.     {
  802.         var url = value( 'input_net_rtsp_url' );
  803.         if( url.substring(0,7) != "rtsp://" )
  804.             mrl.value += "rtsp://";
  805.         mrl.value += url;
  806.     }
  807.  
  808.     if( checked( "input_net_timeshift" ) )
  809.         mrl.value += " :access-filter=timeshift";
  810. }
  811.  
  812. /* update the input MRL using data from the input fake helper */
  813. function update_input_fake()
  814. {
  815.     var mrl = document.getElementById( 'input_mrl' );
  816.  
  817.     mrl.value = "fake:";
  818.     mrl.value += " :fake-file=" + value( "input_fake_filename" );
  819.  
  820.     if( value( "input_fake_width" ) )
  821.         mrl.value += " :fake-width=" + value( "input_fake_width" );
  822.     if( value( "input_fake_height" ) )
  823.         mrl.value += " :fake-height=" + value( "input_fake_height" );
  824.     if( value( "input_fake_ar" ) )
  825.         mrl.value += " :fake-ar=" + value( "input_fake_ar" );
  826. }
  827.  
  828. /**********************************************************************
  829.  * Sout dialog functions
  830.  *********************************************************************/
  831. /* toggle show the full sout interface */
  832. function toggle_show_sout_helper()
  833. {
  834.     var element = document.getElementById( "sout_helper" );
  835.     if( element.style.display == 'block' )
  836.     {
  837.         element.style.display = 'none';
  838.         document.getElementById( "sout_helper_toggle" ).value = 'Full sout interface';
  839.     }
  840.     else
  841.     {
  842.         element.style.display = 'block';
  843.         document.getElementById( "sout_helper_toggle" ).value = 'Hide sout interface';
  844.     }
  845. }
  846.  
  847. /* update the sout MRL using data from the sout_helper */
  848. function update_sout()
  849. {
  850.     var mrl = document.getElementById( 'sout_mrl' );
  851.     mrl.value = "";
  852.  
  853.     check_and_replace_int( 'sout_http_port', 8080 );
  854.     check_and_replace_int( 'sout_mmsh_port', 8080 );
  855.     check_and_replace_int( 'sout_rtp_port', 1234 );
  856.     check_and_replace_int( 'sout_udp_port', 1234 );
  857.     check_and_replace_int( 'sout_ttl', 1 );
  858.  
  859.     if( checked( 'sout_soverlay' ) )
  860.     {
  861.         disable( 'sout_scodec' );
  862.         disable( 'sout_sub' );
  863.     }
  864.     else
  865.     {
  866.         enable( 'sout_scodec' );
  867.         enable( 'sout_sub' );
  868.     }
  869.  
  870.     var transcode =  checked( 'sout_vcodec_s' ) || checked( 'sout_acodec_s' )
  871.                   || checked( 'sout_sub' )      || checked( 'sout_soverlay' );
  872.  
  873.     if( transcode )
  874.     {
  875.         mrl.value += ":sout=#transcode{";
  876.         var alot = false; /* alot == at least one transcode */
  877.         if( checked( 'sout_vcodec_s' ) )
  878.         {
  879.             mrl.value += "vcodec="+value( 'sout_vcodec' )+",vb="+value( 'sout_vb' )+",scale="+value( 'sout_scale' );
  880.             alot = true;
  881.         }
  882.         if( checked( 'sout_acodec_s' ) )
  883.         {
  884.             if( alot ) mrl.value += ",";
  885.             mrl.value += "acodec="+value( 'sout_acodec' )+",ab="+value( 'sout_ab' );
  886.             if( value( 'sout_channels' ) )
  887.                 mrl.value += ",channels="+value( 'sout_channels' );
  888.             alot = true;
  889.         }
  890.         if( checked( 'sout_soverlay' ) )
  891.         {
  892.             if( alot ) mrl.value += ",";
  893.             mrl.value += "soverlay";
  894.             alot = true;
  895.         }
  896.         else if( checked( 'sout_sub' ) )
  897.         {
  898.             if( alot ) mrl.value += ",";
  899.             mrl.value += "scodec="+value( 'sout_scodec' );
  900.             alot = true;
  901.         }
  902.         mrl.value += value( 'sout_transcode_extra' );
  903.             
  904.         mrl.value += "}";
  905.     }
  906.  
  907.     var output = checked( 'sout_display' ) + checked( 'sout_file' )
  908.                + checked( 'sout_http' )    + checked( 'sout_mmsh' )
  909.                + checked( 'sout_rtp' )     + checked( 'sout_udp' );
  910.  
  911.     if( output )
  912.     {
  913.         if( transcode )
  914.             mrl.value += ":";
  915.         else
  916.             mrl.value += ":sout=#";
  917.         var aloo = false; /* aloo == at least one output */
  918.         var mux = radio_value( 'sout_mux' );
  919.         var ttl = parseInt( value( 'sout_ttl' ) );
  920.         if( output > 1 ) mrl.value += "duplicate{";
  921.         if( checked( 'sout_display' ) )
  922.         {
  923.             if( output > 1 ) mrl.value += "dst="
  924.             mrl.value += "display";
  925.             aloo = true;
  926.         }
  927.         if( checked( 'sout_file' ) )
  928.         {
  929.             if( aloo ) mrl.value += ",";
  930.             if( output > 1 ) mrl.value += "dst="
  931.             mrl.value += "std{access=file,mux="+mux+",dst="+value( 'sout_file_filename' )+"}";
  932.             aloo = true;
  933.         }
  934.         if( checked( 'sout_http' ) )
  935.         {
  936.             if( aloo ) mrl.value += ",";
  937.             if( output > 1 ) mrl.value += "dst="
  938.             mrl.value += "std{access=http,mux="+mux+",dst="+value( 'sout_http_addr' );
  939.             if( value( 'sout_http_port' ) )
  940.                 mrl.value += ":"+value( 'sout_http_port' );
  941.             mrl.value += "}";
  942.             aloo = true;
  943.         }
  944.         if( checked( 'sout_mmsh' ) )
  945.         {
  946.             if( aloo ) mrl.value += ",";
  947.             if( output > 1 ) mrl.value += "dst="
  948.             mrl.value += "std{access=mmsh,mux="+mux+",dst="+value( 'sout_mmsh_addr' );
  949.             if( value( 'sout_mmsh_port' ) )
  950.                 mrl.value += ":"+value( 'sout_mmsh_port' );
  951.             mrl.value += "}";
  952.             aloo = true;
  953.         }
  954.         if( checked( 'sout_rtp' ) )
  955.         {
  956.             if( aloo ) mrl.value += ",";
  957.             if( output > 1 ) mrl.value += "dst="
  958.             mrl.value += "std{access=rtp";
  959.             if( ttl ) mrl.value += "{ttl="+ttl+"}";
  960.             mrl.value += ",mux="+mux+",dst="+value( 'sout_rtp_addr' );
  961.             if( value( 'sout_rtp_port' ) )
  962.                 mrl.value += ":"+value( 'sout_rtp_port' );
  963.             if( checked( 'sout_sap' ) )
  964.             {
  965.                 mrl.value += ",sap";
  966.                 if( value( 'sout_sap_group' ) != '' )
  967.                 {
  968.                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
  969.                 }
  970.                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
  971.             }
  972.             mrl.value += "}";
  973.             aloo = true;
  974.         }
  975.         if( checked( 'sout_udp' ) )
  976.         {
  977.             if( aloo ) mrl.value += ",";
  978.             if( output > 1 ) mrl.value += "dst="
  979.             mrl.value += "std{access=udp";
  980.             if( ttl ) mrl.value += "{ttl="+ttl+"}";
  981.             mrl.value += ",mux="+mux+",dst="+value( 'sout_udp_addr' );
  982.             if( value('sout_udp_port' ) )
  983.                 mrl.value += ":"+value( 'sout_udp_port' );
  984.             if( checked( 'sout_sap' ) )
  985.             {
  986.                 mrl.value += ",sap";
  987.                 if( value( 'sout_sap_group' ) != '' )
  988.                 {
  989.                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
  990.                 }
  991.                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
  992.             }
  993.             mrl.value += "}";
  994.             aloo = true;
  995.         }
  996.         if( output > 1 ) mrl.value += "}";
  997.     }
  998.  
  999.     if( ( transcode || output ) && checked( 'sout_all' ) )
  1000.         mrl.value += " :sout-all";
  1001. }
  1002.  
  1003. /* reset sout mrl value */
  1004. function reset_sout()
  1005. {
  1006.     document.getElementById('sout_mrl').value = value('sout_old_mrl');
  1007. }
  1008.  
  1009. /* save sout mrl value */
  1010. function save_sout()
  1011. {
  1012.     document.getElementById('sout_old_mrl').value = value('sout_mrl');
  1013. }
  1014.  
  1015. /**********************************************************************
  1016.  * Browser dialog functions
  1017.  *********************************************************************/
  1018. /* only browse() should be called directly */
  1019. function browse( dest )
  1020. {
  1021.     document.getElementById( 'browse_dest' ).value = dest;
  1022.     document.getElementById( 'browse_lastdir' ).value;
  1023.     browse_dir( document.getElementById( 'browse_lastdir' ).value );
  1024.     show( 'browse' );
  1025. }
  1026. function browse_dir( dir )
  1027. {
  1028.     document.getElementById( 'browse_lastdir' ).value = dir;
  1029.     loadXMLDoc( 'requests/browse.xml?dir='+encodeURIComponent(dir), parse_browse_dir );
  1030. }
  1031. function browse_path( p )
  1032. {
  1033.     document.getElementById( value( 'browse_dest' ) ).value = p;
  1034.     hide( 'browse' );
  1035.     document.getElementById( value( 'browse_dest' ) ).focus();
  1036. }
  1037.  
  1038. /**********************************************************************
  1039.  * Periodically update stuff in the interface
  1040.  *********************************************************************/
  1041. function loop_refresh_status()
  1042. {
  1043.     setTimeout( 'loop_refresh_status()', 1000 );
  1044.     update_status();
  1045. }
  1046. function loop_refresh_playlist()
  1047. {
  1048.     /* setTimeout( 'loop_refresh_playlist()', 10000 ); */
  1049.     update_playlist();
  1050. }
  1051. function loop_refresh()
  1052. {
  1053.     setTimeout( 'loop_refresh_status()', 1 );
  1054.     setTimeout( 'loop_refresh_playlist()', 1 );
  1055. }
  1056.  
  1057.