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