functions.js
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:39k
源码类别:

midi

开发平台:

Unix_Linux

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