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