Add support for displaying the year; put the album in italics. (Feature request...
[patchfork.git] / std / command.js
1 /* 
2     Pitchfork Music Player Daemon Client
3     Copyright (C) 2007  Roger Bystrøm
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; version 2 of the License.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 var position_txt_node = null;
20 var bitrate_txt_node = null;
21 var ALBUMART_URL = "metadata.php?pic=";
22 var OUTPUT_ID = "output_";
23
24 var DIR_SEPARATOR = "/";
25
26 var STATUS_DEFAULT_TIMEOUT = 10;
27
28 /* todo: put these in an object, no reason for them to be lying around here */
29 var last_update_cmd_id;
30 var problem_update_delay = 5;
31 var last_update = -1; 
32 var pl = new Array();
33 var possliderid = -1;
34 var volsliderid = -1;
35 var playing = new Object();
36 playing.id = -1;
37 playing.pos = -1;
38 playing.length = 0;
39 playing.pl_version = 0;
40 playing.pl_size = 0;
41 playing.size = 0;
42 playing.artist = "";
43 playing.album = "";
44 playing.year = "";
45 playing.title = "";
46 playing.image = "";     // 
47 playing.asin = "";      
48 playing.random = 0;     // random on/off
49 playing.repeat = 0;     // repeat on/off
50 playing.xfade = 0;      // crossfade seconds
51 playing.update = false; // dbupdate
52 playing.show_node = null; // node that is supposed to have playing status
53 playing.is_stream = false; // true if the playing song is a stream
54 playing.error = false;
55 playing.error_time = 0;
56
57 playing.state = "";
58 playing.volume = -1;
59 playing.TIME_ELAPSED = 0; 
60 playing.TIME_REMAINING = 1;
61 playing.TIME_END = 2; 
62 playing.time_dtype = playing.TIME_ELAPSED;
63
64 /* various elements found around the document */
65 playing.disp_info = null;
66 playing.pp_button = null;
67 playing.disp_artist = null;
68 playing.disp_title = null; 
69 playing.disp_album = null;
70 playing.disp_year = null;
71 playing.albumart = null;
72
73 var last_pl_selected = true;
74
75 var output_toggle_id = null;
76
77 var pl_overlay_id = -1;
78 var pl_overlay_write = null;
79
80 var status_bar = null;
81
82 var send_command_rm_status = false;
83 var pl_entry_clone = null;
84
85 var settings_time = 10;
86
87 var need_info_arr = null;
88
89 var init_failed = false;
90
91 var playlist_add_popup = null;
92 var playlist_save_popup = null;
93
94 var pagination = new Object();
95 pagination.max = 0; // max pr. page
96 pagination.page = 0; // what page we currently are on
97 pagination.pages = 0; // number of pages being advertised
98 pagination.need_update = false; // indicates wheter we need an update
99 pagination.list = null; // reference to the displaying area
100 pagination.container = null; // reference to the container
101
102 function init_player() {
103         try {
104                 status_bar = new StatusBar();
105
106                 if(update_delay) {
107                         if(update_delay<0)
108                                 update_delay = 1;
109                         update_delay = update_delay * 1000;
110                 }
111                 else window.update_delay = 1000;
112
113                 possliderid = setup_slider(document.getElementById('posslider'), position_adjust, LANG.POSITION);
114                 set_slider_pos(possliderid, 0);
115                 
116                 volsliderid = setup_slider(document.getElementById('volslider'), volume_adjust, LANG.VOLUME);
117                 set_slider_pos(volsliderid, 0);
118
119                 playlist_element = document.getElementById('playlist')
120         
121                 var pltmp_id = setup_node_move(playlist_element, playlist_move, playlist_get_move_txt);
122                 add_move_doubleclick(pltmp_id, playlist_dblclick);
123                 set_selection_change_handler(pltmp_id, pl_selection_changed);
124                 
125                 pl_overlay_id = setup_overlay(playlist_element, new Array(10, 10, 300, 300 ), pl_overlay_open_cb, pl_overlay_close_cb);
126                 pl_overlay_write = get_overlay_write_area(pl_overlay_id);
127
128                 playing.disp_info =  document.getElementById('disp_info');
129                 playing.disp_artist = document.getElementById('disp_artist');
130                 playing.disp_title = document.getElementById('disp_title');
131                 playing.disp_album = document.getElementById('disp_album');
132                 playing.disp_year = document.getElementById('disp_year');
133                 playing.albumart = document.getElementById("albumart");
134                 playing.pp_button = document.getElementById("pp_button");
135
136                 pagination.list = document.getElementById('pagination_list');
137                 pagination.container = document.getElementById('pagination');
138                 pagination.max = pagination_max; // nice :S
139
140                 var tmp = setting_get("time_dtype");
141
142                 if(tmp==null) {
143                         setting_set("time_dtype", playing.time_dtype);
144                 }
145                 else {
146                         if(tmp==playing.TIME_ELAPSED)
147                                 playing.time_dtype = playing.TIME_ELAPSED;
148                         else if(tmp==playing.TIME_REMAINING)
149                                 playing.time_dtype = playing.TIME_REMAINING;
150                 }
151                 
152                 xpath_init();
153                 buttons_init();
154                 setup_keys(); 
155                 pagination_init();
156                 sidebar_init();
157                 plsearch_init();
158                 streaming_init();
159
160                 if(typeof(window.metadata_init)=='function')
161                         metadata_init();
162                 if(typeof(window.recommend_init)=='function')
163                         recommend_init();
164                 playlist_init();
165         }
166         catch(e) {
167                 init_failed = true;
168                 debug(LANG.E_INIT +": " + e.message, true);
169         }
170 }
171
172 /* arg-list: command to send, command to call when result is return, show status message when working, 
173         don't request status update with this sendcommand, 
174         post data if we should use that, if it should form-urlencoded content type should be set */
175 function send_command(command, result_callback, status_msg, nostatus, do_post, form_urlencoded) {
176         if(init_failed)
177                 return;
178
179         var http = new XMLHttpRequest(); 
180         var url = "command.php?" + command;
181
182         if(!nostatus) {
183           url+="&plchanges=" + playing.pl_version;
184           if(pagination.max>0) {
185                 url+="&pmax=" + pagination.max + "&page=" + pagination.page;
186                 //debug("pmax: " + pagination.max + ", page: " + pagination.page);
187           }
188         }
189
190         if(send_command_rm_status) {
191                 hide_status_bar();
192                 send_command_rm_status = false;
193         }
194
195         http.onreadystatechange = function() {
196           if(http.readyState==4) {
197                 var resp = null;
198                 if(http.responseText&&(resp = evaluate_json(http.responseText))) {
199                         if(resp['connection']&&resp['connection']=="failed") {
200                                 last_update = get_time();
201                                 show_status_bar(LANG.E_CONNECT);
202                                 send_command_rm_status = true;
203                                 try {
204                                         result_callback("failed");
205                                 }
206                                 catch(e) {}
207                                 return;
208                         }
209                 }
210                 else {
211                         show_status_bar(LANG.E_INVALID_RESPONSE);
212                         send_command_rm_status = true;
213                         last_update = get_time();
214                         try {
215                                 result_callback("failed");
216                         }
217                         catch(e) {}
218                         return;
219                 }
220
221             if(http.status==200) {
222                 var res = resp['result'];
223                 var stat = resp["status"];
224                 var plchanges = resp["plchanges"];
225                 var has_plchanges = plchanges && stat && playing.pl_version != stat.playlist;
226
227                 if(res&&result_callback) {
228                         result_callback(res);
229                 }
230
231                 if(stat) {
232                         current_status_handler(stat, has_plchanges);
233                         last_update = get_time();
234                 }
235
236                 if(has_plchanges) {
237                         playing.pl_version = stat.playlist;
238                         plchanges_handler3(plchanges, stat.playlistlength);
239                         /* the currently playing song might have changed if it's a stream */
240                         if(playing.is_stream) {
241                                 request_song_info();
242                         }
243                 }
244
245                 /* don't remove if there's no message or a timer */
246                 if(status_msg&&!status_bar.timer)
247                         hide_status_bar();
248             }
249             else {
250                 if(result_callback) { 
251                         result_callback("server operation failed");
252                 }
253                 show_status_bar(LANG.NO_RESPONSE); // maybe add a 10 second delay here and reconnect!
254                 send_command_rm_status = true;
255             }
256           }
257         }
258
259         if(status_msg) {
260                 show_status_bar(status_msg, true);
261         }
262
263
264         if(do_post) {
265                 http.open("POST", url);
266                 if(form_urlencoded) {
267                         http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
268                 }
269                 http.send(do_post);
270         }
271         else {
272                 http.open("GET", url);  
273                 http.send(null);
274         }
275 }
276
277 function update_callback(res) {
278         var time = update_delay;
279         if(res=="failed")
280                 time = problem_update_delay*update_delay;
281         last_update_cmd_id = setTimeout(need_update, time);
282 }
283
284 function reschedule_update_now() {
285         clearTimeout(last_update_cmd_id);
286         // make sure it get's run immidiately
287         last_update_cmd_id = setTimeout(need_update, 0, -update_delay);
288 }
289
290 function need_update(delay) {
291         if(!delay)
292            delay = 0;
293         var now = get_time();
294         if(now>last_update+update_delay+delay-20) { // giving it a little slack
295                 send_command("ping", update_callback);
296         }
297         else {
298                 delay = last_update+update_delay-now;
299                 if(delay<10)
300                         delay = 10;
301                         
302                 last_update_cmd_id = setTimeout(need_update, delay);
303         }
304 }
305
306 /* stop program */
307 function handle_fatal_error(txt) {
308         show_status_bar(txt);
309         clearTimeout(last_update_cmd_id);
310 }
311
312 /* current status handler, info is stats
313  * if has_plchanges it is assumed the data also carries plchanges 
314  * which will handle resizing of the playlist */
315 function current_status_handler(info, has_plchanges) {
316         if(!info) {
317                 // something is wrong
318                 set_slider_pos(possliderid, 0);
319                 return;
320         }
321         
322         var tmp = info.playlistlength;
323         if((tmp = parseInt(tmp))>=0) {
324                 if(playing.pl_size!=tmp) {
325                         playing.pl_size = tmp;
326                         if(pagination.max>0) {
327                                 // make sure size fits inside what we have as number of pages
328                                 var s = pagination.max * (pagination.pages);
329                                 if(tmp < s-pagination.max || tmp>=s) {
330                                         pagination_update_list(tmp);
331                                 }
332                                 if(!has_plchanges) {
333                                         playlist_resize(tmp); 
334                                 }
335                         }
336                         else if(!has_plchanges) { // if it doesn't carry plchanges we have to do it here
337                                 playlist_resize(tmp); 
338                         }
339                 }
340         }
341
342         tmp = info.updating_db;
343         if(tmp) {
344                 tmp = parseInt(tmp);
345                 if(playing.update!=tmp) {
346                         playing.update = tmp;
347                         show_status_bar(LANG.WAIT_UPDATING_DB, true);
348                 }
349         }
350         else if(playing.update) {
351                 playing.update = false;
352                 hide_status_bar();
353         }
354         
355         var state = info["state"];
356         var volume = info[ "volume"];
357         if(volume!=null&&volume!=playing.volume) {
358                 set_slider_pos(volsliderid, volume);
359                 playing.volume = volume;
360         }
361
362         playing.repeat = info.repeat;
363         playing.random = info.random;
364         playing.xfade = info.xfade;
365
366         if(state!="stop") {
367                 
368                 var pos = info["time"].split(":");
369                 set_slider_pos(possliderid, (pos[0]*100)/pos[1]);
370                 playing.length = pos[1];
371
372                 /* complex, but seems to be somewhat better in firefox */
373                 var tmp = info.bitrate;
374                 if(tmp&&playing.bitrate!=tmp) {
375                         var disp_info = playing.disp_info
376                         if(bitrate_txt_node==null) {
377                                 bitrate_txt_node = document.createTextNode(LANG.BITRATE);
378                                 disp_info.appendChild(bitrate_txt_node);
379                                 if(disp_info.normalize)
380                                         disp_info.normalize();
381                                 bitrate_txt_node = disp_info.firstChild.splitText(LANG.BITRATE.length);
382                         }
383                         var rep = document.createTextNode(tmp);
384                         disp_info.replaceChild(rep, bitrate_txt_node);
385                         bitrate_txt_node = rep;
386                         playing.bitrate = tmp;
387                 }
388
389                 var postxt = get_slider_txt(possliderid);
390                 if(postxt) {
391                         if(position_txt_node==null) {
392                                 position_txt_node = postxt.firstChild.splitText(LANG.POSITION.length);
393                         }
394                         var rep = create_txt(format_playing_time(pos[0], pos[1]));
395                         postxt.replaceChild(rep, position_txt_node);
396                         position_txt_node = rep; 
397                 }
398         }
399         else if(playing.state!="stop") { // state == stop and last state wasn't stop
400                 set_slider_pos(possliderid, 0);
401                 var disp_info = playing.disp_info;
402                 var rep = document.createTextNode("0");
403                 var postxt = get_slider_txt(possliderid);
404                 if(bitrate_txt_node&&bitrate_txt_node!=null) {
405                         disp_info.replaceChild(rep, bitrate_txt_node);
406                         bitrate_txt_node = rep;
407                 }
408                 playing.bitrate = 0;
409                 rep = document.createTextNode("");
410                 if(position_txt_node&&position_txt_node!=null) {
411                         postxt.replaceChild(rep, position_txt_node);
412                         position_txt_node = rep; 
413                 }
414         }
415         if(state!=playing.state) {
416                 playing.state = state;
417                 var bt = playing.pp_button;
418                 if(state=="play") {
419                         bt.src = IMAGE.BUTTON_PAUSE;
420                         if(typeof(window.streaming_try_autoplay)=='function')
421                                 streaming_try_autoplay();
422                 }
423                 else {
424                         bt.src = IMAGE.BUTTON_PLAY;
425                         if(typeof(window.streaming_try_autostop)=='function')
426                                 streaming_try_autostop();
427                 }
428         }
429         
430         if(typeof info.error != 'undefined' || playing.error) {
431                 if(playing.error && get_time() - 10000 > playing.error_time) {
432                         playing.error = false;
433                         hide_status_bar();
434                         send_clear_error();
435                 }
436                 else if(typeof info.error != 'undefined' && playing.error != info.error) {
437                         playing.error = info.error;
438                         playing.error_time = get_time();
439                         show_status_bar("MPD error: " + playing.error);
440                 }
441         }
442
443         var c_play = info.songid;
444         if(typeof(c_play)=='undefined') {
445                 playing.id = -1;
446                 playing.pos = -1;
447                 request_song_info();
448                 select_playing_song();
449         }
450         else if(c_play!=playing.id) {
451                 playing.id = c_play;
452                 playing.pos = parseInt(info.song);
453                 select_playing_song();
454                 if(pagination_is_following()) {
455                         playlist_scroll_to_playing();
456                 }
457                 /* this is last because it needs the id */
458                 request_song_info();
459         }
460         else if(playing.pos!=info.song) {
461                 playing.pos = parseInt(info.song);
462         }
463 }
464
465 function format_playing_time(pos, total) {
466         if(playing.time_dtype==playing.TIME_REMAINING) {
467                 return convert_minsec(pos-total) + "/" + convert_minsec(total);
468         }
469         else { // dtype == playing.TIME_ELAPSED || something wrong
470                 return convert_minsec(pos) + "/" + convert_minsec(total);
471         }
472 }
473
474 function request_song_info() {
475         /* clean up */
476         if(playing.id<0) {
477                 remove_children(playing.disp_artist);
478                 remove_children(playing.disp_title);
479                 remove_children(playing.disp_album);
480                 if(playing.disp_year)
481                         remove_children(playing.disp_year);
482                 if(playing.albumart)
483                         remove_children(playing.albumart);
484                 playing.artist = "";
485                 playing.title = "";
486                 playing.album = "";
487                 playing.year = "";
488                 playing.image = "";
489                 playing.asin = "";
490                 playing.length = "";
491                 playing.is_stream = false;
492                 set_playing_title();
493         }
494         else {
495                 /* or update */
496                 send_command("currentsong", update_current_song, false, true);
497         }
498 }
499
500 function update_current_song(info) {
501         var artist = info[ "Artist"];
502         var title = info["Title"];
503         var album = info[ "Album"];
504         var year = (info["Year"] == null) ? info["Date"] : info["Year"];
505         var a = playing.disp_artist;
506         var t = playing.disp_title;
507         var alb = playing.disp_album;
508         var y = playing.disp_year;
509         var new_thumb = false;
510
511         if(typeof(title)=='undefined')
512                 title = "";
513         if(typeof(album)=='undefined')
514                 album = "";
515         if(typeof(artist)=='undefined')
516                 artist = "";
517         if(typeof(year)=='undefined')
518                 year = "";
519         else
520                 year = "["+year+"]";
521
522         if(artist!=playing.artist) {
523                 playing.artist = artist;
524                 new_thumb = true;
525                 remove_children(a);
526                 a.appendChild(create_txt(artist));
527         }
528         if(playing.album != album) {
529                 playing.album = album;
530                 new_thumb = true;
531                 remove_children(alb);
532                 alb.appendChild(create_txt(album));
533         }
534         if((playing.year != year) && y) {
535                 playing.year = year;
536                 new_thumb = true;
537                 remove_children(y);
538                 y.appendChild(create_txt(year));
539         }
540
541         if(typeof(info['file'])!='undefined') {
542                 var f = info['file'];
543                 if(f&&f.indexOf("http://")==0)
544                         playing.is_stream = true;
545                 else playing.is_stream = false;
546         }
547
548         remove_children(t);
549         playing.title = title;
550
551         if(title==null||title=="") {
552                 title = info["file"];
553                 if(title)
554                         title = title.substring(title.lastIndexOf(DIR_SEPARATOR)+1);
555         }
556         t.appendChild(create_txt(title));
557
558         set_playing_title(artist, title);
559
560         if(new_thumb&&typeof(window.request_thumbnail) == 'function') {
561                 setTimeout(request_thumbnail, 1);
562         }
563 }
564
565 function set_playing_title(artist, title) {
566         if(typeof(artist)=='undefined'||artist==null)
567                 artist = "";
568         if(typeof(title)=='undefined'||title==null)
569                 title = "";
570         
571         var wt = "Pitchfork MPD Client";
572         if(artist.length||title.length) {
573                 wt = artist;
574                 if(title.length)
575                         wt += " - " + title;
576         }
577         document.title = wt;
578 }
579
580 function volume_adjust(vol) {
581         send_command("volume=" + parseInt(vol));
582 }
583
584 function position_adjust(pos) {
585         send_command("position=" + parseInt((pos* parseInt(playing.length))/100) + "&id=" + playing.id);
586 }
587
588 function convert_minsec(sec) {
589         var min = parseInt(sec/60);
590         var s = Math.abs(sec%60);
591         return (sec<0&&min==0?"-" + min:min)  + ":" + (s<10?"0" + s:s);
592 }
593
594 function buttons_init() {
595         
596         /* player control */
597         var elem = document.getElementById('pp_button');
598         elem.src = IMAGE.BUTTON_PLAY;
599         add_listener(elem, "click", send_play_pause);
600         if(window.stop_button) {
601                 elem = document.getElementById('stop_button');
602                 elem.style.display = "";
603                 elem.src = IMAGE.BUTTON_STOP;
604                 add_listener(elem, "click", send_stop_cmd);
605                 elem.parentNode.style.marginLeft = "-15px";
606         }
607
608         elem = document.getElementById("next_button");
609         elem.src = IMAGE.BUTTON_NEXT;
610         add_listener(elem, "click", send_next_song);
611         elem = document.getElementById("previous_button");
612         elem.src = IMAGE.BUTTON_PREVIOUS;
613         add_listener(elem, "click", send_previous_song);
614
615         /* left menu buttons */
616         elem = document.getElementById("open_directory_button");
617         elem.src = IMAGE.MENU_ITEM_DIRECTORY;
618         add_listener(elem, "click", open_pl_overlay);
619         elem = document.getElementById("crop_items_button");
620         elem.src = IMAGE.MENU_ITEM_CROP;
621         add_listener(elem, "click", remove_songs_event);
622         elem = document.getElementById("remove_items_button");
623         elem.src = IMAGE.MENU_ITEM_REMOVE;
624         add_listener(elem, "click", remove_songs_event);
625
626         /* server settings */
627         elem = document.getElementById("settings_header");
628         add_listener(elem, "click", open_close_settings);
629         add_listener(elem, "mousedown", stop_event);
630
631         /* playlist */
632         elem = document.getElementById("playlist_add");
633         add_listener(elem, "click", playlist_add_button);
634         elem = document.getElementById("playlist_save");
635         add_listener(elem, "click", playlist_save_button);
636
637         /* status bar */
638         elem = document.getElementById("status_bar_img");
639         elem.src = IMAGE.WORKING;
640
641         /* streaming if applicable */
642         elem = document.getElementById("streaming_open");
643         if(elem) {
644                 add_listener(elem, "click", streaming_open);
645         }
646
647         /* time display */
648         elem = get_slider_txt(possliderid);
649         if(elem) {
650                 add_listener(elem, "click", change_pos_dtype);
651         }
652
653         // pagination
654         elem = document.getElementById("pagination");
655         if(elem) {
656                 add_listener(elem, "click", pagination_change_page);
657                 add_listener(elem, "mousemove", pagination_scroll_view);
658                 add_listener(elem, "mouseout", pagination_scroll_stop);
659         }
660         elem = document.getElementById("pagination_jump_current");
661         if(elem) {
662                 elem.src = IMAGE.JUMP_CURRENT;
663                 add_listener(elem, "click", playlist_scroll_to_playing);
664                 elem.title = LANG.JUMP_CURRENT;
665         }
666         elem = document.getElementById("pagination_follow_current");
667         if(elem) {
668                 add_listener(elem, "click", pagination_toggle_following);
669         }
670
671         elem = document.getElementById("playlist_search_btn");
672         if(elem) {
673                 add_listener(elem, "click", plsearch_open);
674         }
675
676         // set it to nothing selected
677         pl_selection_changed(false);
678 }
679
680 function send_play_pause(e) {
681         stop_event(e);
682         var act = "toggle";
683         if(playing.state=="stop") {
684                 act = "play";
685                 if(playing.id>=0)
686                         act+="&id=" + playing.id;
687         }
688         send_command("act=" + act);
689 }
690 function send_stop_cmd(e) {
691         stop_event(e);
692         send_command("act=stop");
693 }
694 function send_next_song(e) {
695         stop_event(e);
696         send_command("act=next");
697 }
698 function send_previous_song(e) {
699         stop_event(e);
700         send_command("act=previous");
701 }
702
703 function send_update_db_cmd(e) {
704         stop_event(e);
705         send_command("updatedb");
706 }
707
708 function send_clear_error() {
709         send_command("clearerror", false, false, true);
710 }
711
712 function remove_songs_event(e) {
713         var inv = 'crop_items_button'==e.target.id;
714         var sel = get_pl_selection_range(inv);
715         if(!inv) {
716                 /* nothing selected if we just removed it, 
717                  * or at least in theory */
718                 pl_selection_changed(false);
719         }
720         if(sel.length==0) {
721                 return;
722         }
723         send_command("remove=" + encodeURIComponent(sel), remove_songs_cb, LANG.WAIT_REMOVING);
724 }
725
726 function remove_songs_cb(response) {
727         if(response!="ok") {
728                 show_status_bar(LANG.E_REMOVE);
729                 hide_status_bar(STATUS_DEFAULT_TIMEOUT);
730         }
731 }
732
733 function open_close_settings(e) {
734         var sc = document.getElementById('settings_container');
735         /* close */
736         if(sc.style.display == "block") { /* not perfect but I think there's enough vars at the top */
737                 sc.firstChild.style.display = "none";
738                 remove_listener(sc, "mousedown", stop_event);
739                 remove_listener(sc, "click", settings_click_handler);
740                 setTimeout(open_close_settings_timer, settings_time, sc, false, new Array(0, 200));
741         }
742         else { 
743         /* open */
744                 var dst_height = sc.scrollHeight; // || innerHeight
745                 sc.style.height = "50px";
746                 sc.style.overflow = "hidden";
747                 remove_children(sc.firstChild);
748                 sc.firstChild.style.display = "none";
749                 sc.firstChild.appendChild(document.createTextNode("Loading.."));
750                 sc.style.display = "block"; 
751                 add_listener(sc, "mousedown", stop_event);
752                 add_listener(sc, "click", settings_click_handler);
753                 setTimeout(open_close_settings_timer, settings_time, sc, true, new Array(0, 200));
754                 send_command("outputs", open_settings_cb);
755         }
756 }
757
758 function open_close_settings_timer(sc, isOpening, heights) {
759         var ad = 50;
760         if(isOpening)
761                 heights[0] += ad;
762         else heights[1] -=ad;
763         
764         if(heights[0]<heights[1]) {
765                 sc.style.height = (isOpening?heights[0]:heights[1]) + "px";
766                 setTimeout(open_close_settings_timer, settings_time, sc, isOpening, heights);
767         }
768         else {
769                 if(isOpening) {
770                         //sc.style.overflow = "auto";
771                         sc.firstChild.style.display = "block";
772                         sc.style.height = heights[1] + "px";
773                 }
774                 else {
775                         sc.style.display = "none";
776                         sc.style.height = heights[0] + "px";
777                 }
778         }
779
780 }
781
782 function create_settings_status_image(stat) {
783         var img = create_node("img");
784         img.className = "server_settings";
785         if(stat==1||stat=="1") {
786                 img.src = IMAGE.SERVER_SETTINGS_ENABLED;
787         }
788         else {
789                 img.src = IMAGE.SERVER_SETTINGS_DISABLED;
790         }
791         return img;
792 }
793
794 function open_settings_cb(response) {
795         var txt = document.getElementById('settings_content');
796         remove_children(txt);
797         var img = create_node("img");
798         img.className = "server_settings";
799
800         function add_entry(id, stat, text, no_img) {
801                 var span = create_node("span", id);
802                 span.className = "server_settings";
803                 if(!no_img) {
804                         var im = create_settings_status_image(stat);
805                         im.id = id + "_img";
806                         span.appendChild(im);
807                 }
808                 span.appendChild(create_txt(" " + text));
809                 txt.appendChild(span);
810                 txt.appendChild(create_node("br"));
811                 return span;
812         }
813
814         add_entry("repeat_toggle", playing.repeat, LANG.REPEAT);
815         add_entry("random_toggle", playing.random, LANG.RANDOM);
816         var xfade = add_entry("xfade_entry", playing.xfade, LANG.XFADE, true);
817         var xe = create_node("img");
818         xe.name = "left";
819         xe.className = "server_settings";
820         xe.src = IMAGE.SERVER_SETTINGS_XFADE_DOWN;
821         xfade.appendChild(xe);
822         var i_right = xe.cloneNode(true);
823         i_right.name = "right";
824         i_right.src = IMAGE.SERVER_SETTINGS_XFADE_UP;
825         xe = create_node("span", "xfade_adjust_txt", " " + playing.xfade + " ");
826         xfade.appendChild(xe);
827         xfade.appendChild(i_right);
828
829         var tmp = create_node("hr"); 
830         tmp.className = "server_settings";
831         txt.appendChild(tmp);
832         txt.appendChild(create_txt("Outputs:"));
833         txt.appendChild(create_node("br"));
834         try {
835                 var outputs = response['outputs'];
836                 for(var i in outputs) {
837                         var id = outputs[i]["outputid"];
838                         var enabled = outputs[i]["outputenabled"];
839                         var s = add_entry(OUTPUT_ID + id, enabled, outputs[i]["outputname"]);
840                         s.setAttribute("outputenabled", enabled);
841                 }
842         }
843         catch(e) {
844                 debug(e.message);
845                 txt.appendChild(create_txt(LANG.E_NO_OUTPUTS));
846         }
847 }
848
849 function settings_click_handler(e) {
850         for(var n = e.target; n.parentNode; n=n.parentNode) {
851                 if(n.id) {
852                         if(n.id.indexOf(OUTPUT_ID)==0&&n.id.indexOf("img")<0) {
853                                 toggle_output(n);
854                                 break;
855                         }
856                         else if(n.id=="repeat_toggle") {
857                                 toggle_repeat(n);
858                                 break;
859                         }
860                         else if(n.id=="random_toggle") {
861                                 toggle_random(e);
862                                 break;
863                         }
864                         else if(n.id=="xfade_entry") {
865                                 xfade_adjust(n, e);
866                         }
867                         else if(n.id=="settings_container") {
868                                 break;
869                         }
870                 }
871         }
872         stop_event(e);
873 }
874
875 function toggle_repeat(e) {
876         send_command("repeat=" + (parseInt(playing.repeat)==0?1:0), toggle_repeat_cb);
877 }
878 function toggle_random(e) {
879         send_command("random=" + (parseInt(playing.random)==0?1:0), toggle_random_cb);
880 }
881 function toggle_output(e) {
882         target = e;
883         output_toggle_id = target.id;
884         id = target.id.substring(OUTPUT_ID.length);
885         var cmd = "output_";
886         if(target.getAttribute("outputenabled")==1)
887                 cmd+="d";
888         else cmd+="e";
889         cmd+="=" + id;
890         send_command(cmd, output_change_cb);
891 }
892
893 function xfade_adjust(node, ev) {
894         if(!ev.target.name) {
895                 return;
896         }
897         var name = ev.target.name;
898         if(name!="left"&&name!="right") {
899                 return;
900         }
901         var xfade= parseInt(playing.xfade) + ("left"==name?-1:+1);
902         if(xfade<0)
903                 xfade=0;
904         send_command("xfade=" + xfade);
905         var x = document.getElementById("xfade_adjust_txt");
906         if(x.firstChild) {
907                 x.firstChild.nodeValue = " " + xfade + " ";
908         }
909 }
910
911 function toggle_repeat_cb(response) {
912         var n = document.getElementById("repeat_toggle_img");
913         var img = create_settings_status_image(response);
914         replace_node(img, n);
915         img.id = "repeat_toggle_img";
916 }
917 function toggle_random_cb(response) {
918         var n = document.getElementById("random_toggle_img");
919         var img = create_settings_status_image(response);
920         replace_node(img, n);
921         img.id = "random_toggle_img";
922 }
923 function output_change_cb(response) {
924         if(output_toggle_id==null) 
925                 return;
926         var n = document.getElementById(output_toggle_id);
927         if(!n) 
928                 return;
929         var o_img = document.getElementById(output_toggle_id + "_img");
930         n.setAttribute("outputenabled", response);
931         var img = create_settings_status_image(response);
932         img.id = o_img.id;
933         replace_node(img, o_img);
934         output_toggle_id = null;
935 }
936
937
938 function send_play_pos(pos) {
939         send_command("act=play&pos=" + pos);
940 }
941
942 function open_pl_overlay(e) {
943         if(open_overlay_idx<0) {
944                 open_overlay_fixed(pl_overlay_id);
945         }
946         else {
947                 close_overlay(pl_overlay_id);
948         }
949 }
950
951 function StatusBar(txt) {
952         this.txt = document.getElementById('status_bar_txt');
953         this.img = document.getElementById('status_bar_img');
954         this.main = document.getElementById('status_bar');
955         this.timer = false;
956 }
957
958 /* status bar (could be put in toolkit though */
959 function show_status_bar(txt, working) {
960         txt = create_txt(txt);
961         remove_children(status_bar.txt);
962         status_bar.txt.appendChild(txt);
963         if(working) {
964                 status_bar.img.setAttribute("working", "yeah");
965         }
966         else {
967                 if(status_bar.img.hasAttribute("working"))
968                         status_bar.img.removeAttribute("working");
969         }
970         status_bar.main.style.display = "block";
971         /* to prevent it from disappearing again if it is showing */
972         if(status_bar.timer) {
973                 clearTimeout(status_bar.timer);
974                 status_bar.timer = false;
975         }
976 }
977
978 /* hides status-bar after optional number of seconds */
979 function hide_status_bar(time) {
980         if(typeof(time)!='undefined'&&time&&time>0) {
981                 status_bar.timer = setTimeout(hide_status_bar, time*1000, false);
982         }
983         else {
984                 remove_children(status_bar.txt);
985                 if(browser_is_opera()) {
986                         opera_quirk_set_display_none(status_bar.main);
987                 }
988                 else {
989                         status_bar.main.style.display = "none";
990                 }
991                 status_bar.timer = false;
992         }
993 }
994
995 function setup_keys() {
996         keyboard_init(); 
997         keyboard_register_listener(send_play_pause, "k", KEYBOARD_NO_KEY, true);
998         keyboard_register_listener(send_previous_song, "j", KEYBOARD_NO_KEY, true);
999         keyboard_register_listener(send_next_song, "l", KEYBOARD_NO_KEY, true);
1000         keyboard_register_listener(quickadd_focus, "s", KEYBOARD_CTRL_KEY|KEYBOARD_SHIFT_KEY, true);
1001         /* for browsers where ctrl+shift does something else */
1002         keyboard_register_listener(quickadd_focus, "s", KEYBOARD_CTRL_KEY|KEYBOARD_ALT_KEY, true);
1003         keyboard_register_listener(playlist_scroll_to_playing, " " , KEYBOARD_NO_KEY, true);
1004
1005         var qa = document.getElementById('quickadd');
1006         qa.setAttribute("autocomplete", "off");
1007         add_listener(qa, "keydown", quickadd_keydown_handler); // stop it from getting to the keylisteners!
1008         add_listener(qa, "keyup", quickadd_keyup_handler);
1009         add_listener(qa, "focus", quickadd_focus);
1010         add_listener(qa, "blur", quickadd_blur);
1011         qa.title = LANG.QUICK_ADD + " [Ctrl+Shift+S]";
1012 }
1013
1014 function change_pos_dtype() {
1015         playing.time_dtype++;
1016         if(playing.time_dtype>=playing.TIME_END) {
1017                 playing.time_dtype = 0; 
1018         }
1019         setting_set("time_dtype", playing.time_dtype);
1020 }
1021
This page took 0.110002 seconds and 4 git commands to generate.