initial import from pitchfork-0.5.5
[patchfork.git] / std / command.js
CommitLineData
964dd0bc
JW
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
19var position_txt_node = null;
20var bitrate_txt_node = null;
21var ALBUMART_URL = "metadata.php?pic=";
22var OUTPUT_ID = "output_";
23
24var DIR_SEPARATOR = "/";
25
26var STATUS_DEFAULT_TIMEOUT = 10;
27
28/* todo: put these in an object, no reason for them to be lying around here */
29var last_update_cmd_id;
30var problem_update_delay = 5;
31var last_update = -1;
32var pl = new Array();
33var possliderid = -1;
34var volsliderid = -1;
35var playing = new Object();
36playing.id = -1;
37playing.pos = -1;
38playing.length = 0;
39playing.pl_version = 0;
40playing.pl_size = 0;
41playing.size = 0;
42playing.artist = "";
43playing.album = "";
44playing.title = "";
45playing.image = ""; //
46playing.asin = "";
47playing.random = 0; // random on/off
48playing.repeat = 0; // repeat on/off
49playing.xfade = 0; // crossfade seconds
50playing.update = false; // dbupdate
51playing.show_node = null; // node that is supposed to have playing status
52playing.is_stream = false; // true if the playing song is a stream
53playing.error = false;
54playing.error_time = 0;
55
56playing.state = "";
57playing.volume = -1;
58playing.TIME_ELAPSED = 0;
59playing.TIME_REMAINING = 1;
60playing.TIME_END = 2;
61playing.time_dtype = playing.TIME_ELAPSED;
62
63/* various elements found around the document */
64playing.disp_info = null;
65playing.pp_button = null;
66playing.disp_artist = null;
67playing.disp_title = null;
68playing.disp_album = null;
69playing.albumart = null;
70
71var last_pl_selected = true;
72
73var output_toggle_id = null;
74
75var pl_overlay_id = -1;
76var pl_overlay_write = null;
77
78var status_bar = null;
79
80var send_command_rm_status = false;
81var pl_entry_clone = null;
82
83var settings_time = 10;
84
85var need_info_arr = null;
86
87var init_failed = false;
88
89var playlist_add_popup = null;
90var playlist_save_popup = null;
91
92var pagination = new Object();
93pagination.max = 0; // max pr. page
94pagination.page = 0; // what page we currently are on
95pagination.pages = 0; // number of pages being advertised
96pagination.need_update = false; // indicates wheter we need an update
97pagination.list = null; // reference to the displaying area
98pagination.container = null; // reference to the container
99
100function 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 */
172function 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
274function 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
281function 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
287function 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 */
304function 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 */
312function 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
462function 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
471function 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
494function 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
547function 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
562function volume_adjust(vol) {
563 send_command("volume=" + parseInt(vol));
564}
565
566function position_adjust(pos) {
567 send_command("position=" + parseInt((pos* parseInt(playing.length))/100) + "&id=" + playing.id);
568}
569
570function 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
576function 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
662function 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}
672function send_stop_cmd(e) {
673 stop_event(e);
674 send_command("act=stop");
675}
676function send_next_song(e) {
677 stop_event(e);
678 send_command("act=next");
679}
680function send_previous_song(e) {
681 stop_event(e);
682 send_command("act=previous");
683}
684
685function send_update_db_cmd(e) {
686 stop_event(e);
687 send_command("updatedb");
688}
689
690function send_clear_error() {
691 send_command("clearerror", false, false, true);
692}
693
694function 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
708function 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
715function 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
740function 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
764function 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
776function 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
831function 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
857function toggle_repeat(e) {
858 send_command("repeat=" + (parseInt(playing.repeat)==0?1:0), toggle_repeat_cb);
859}
860function toggle_random(e) {
861 send_command("random=" + (parseInt(playing.random)==0?1:0), toggle_random_cb);
862}
863function 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
875function 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
893function 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}
899function 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}
905function 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
920function send_play_pos(pos) {
921 send_command("act=play&pos=" + pos);
922}
923
924function 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
933function 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 */
941function 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 */
961function 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
977function 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
996function 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.098207 seconds and 4 git commands to generate.