]>
Commit | Line | Data |
---|---|---|
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 | ||
19 | /* this file contains anything pertaining to playlist management */ | |
20 | ||
21 | var playlist_element = null; | |
22 | ||
23 | ||
24 | function playlist_init() { | |
25 | show_status_bar(LANG.WAIT_LOADING, true); | |
26 | var http = new XMLHttpRequest(); | |
27 | http.open("GET", "command.php?ping"); | |
28 | remove_children(playlist_element); | |
29 | ||
30 | var c = create_node("tr"); | |
31 | function ctws(size) { | |
32 | var tmp = create_node("td"); | |
33 | tmp.style.width = size + "px"; | |
34 | c.appendChild(tmp); | |
35 | } | |
36 | ctws(23); // pos | |
37 | for(var i=1; i< pl_entries.length-1; i++) { | |
38 | if(pl_entries[i]=="Track") { | |
39 | ctws(50); | |
40 | } | |
41 | else { | |
42 | ctws(200); | |
43 | } | |
44 | } | |
45 | ctws(30); // time | |
46 | c.className = "playlist"; | |
47 | pl_entry_clone = c; | |
48 | ||
49 | http.onreadystatechange = function() { | |
50 | if(http.readyState==4) { | |
51 | var resp = null; | |
52 | if(!http.responseText||!(resp = evaluate_json(http.responseText))) { | |
53 | show_status_bar(LANG.E_INVALID_RESPONSE); | |
54 | throw("Init failed"); | |
55 | } | |
56 | else if(http.status==200) { | |
57 | if(resp['connection']&&resp['connection']=="failed") { | |
58 | show_status_bar(LANG.E_CONNECT); | |
59 | throw(LANG.E_CONNECT); | |
60 | } | |
61 | ||
62 | /* for pagination to work properly we need to know some values in forehand */ | |
63 | if(resp.status) { | |
64 | var s = resp.status; | |
65 | if(typeof(s.song)!='undefined') | |
66 | playing.pos = parseInt(s.song); | |
67 | } | |
68 | ||
69 | if(pagination_is_following()) | |
70 | playlist_scroll_to_playing(); | |
71 | ||
72 | hide_status_bar(1); | |
73 | dirlist_init(); | |
74 | setTimeout(need_update,10); | |
75 | } | |
76 | else { | |
77 | show_status_bar(LANG.E_INIT_PL); | |
78 | throw("init failed"); | |
79 | } | |
80 | } | |
81 | } | |
82 | http.send(null); | |
83 | } | |
84 | ||
85 | function create_lazy_pl_row(info, id) { | |
86 | var tr = null; | |
87 | var pos = parseInt(info["cpos"]); | |
88 | tr = pl_entry_clone.cloneNode(true); | |
89 | tr.firstChild.appendChild(create_txt(parseInt(pos)+1)); | |
90 | tr.setAttribute("plpos", pos); | |
91 | tr.id = id; | |
92 | return tr; | |
93 | } | |
94 | ||
95 | function get_plid(node) { | |
96 | return node.id.substring(7); | |
97 | } | |
98 | ||
99 | function get_plpos(node) { | |
100 | return node.getAttribute("plpos"); | |
101 | } | |
102 | ||
103 | function set_pl_position(node, new_pos) { | |
104 | node.childNodes[0].childNodes[0].nodeValue = (new_pos+1); | |
105 | node.setAttribute("plpos", new_pos); | |
106 | } | |
107 | ||
108 | function moved_plitem(stat) { | |
109 | if(stat!="ok") { | |
110 | show_status_bar(LANG.E_PL_MOVE); | |
111 | hide_status_bar(STATUS_DEFAULT_TIMEOUT); | |
112 | } | |
113 | } | |
114 | ||
115 | function playlist_get_move_txt() { | |
116 | /* todo */ | |
117 | return "Moving selection.."; | |
118 | } | |
119 | ||
120 | /* a note on this... if to is null then it was put first in the list */ | |
121 | /* if move is null then it's a multi-move (which it always will be for now) */ | |
122 | function playlist_move(move, to) { | |
123 | ||
124 | if(move==null) { | |
125 | var range = get_pl_selection_range(false); | |
126 | to = get_plpos(to); | |
127 | send_command("rangemove=" + encodeURIComponent(to) + "&elems=" + encodeURIComponent(range)); | |
128 | return; | |
129 | } | |
130 | ||
131 | if(to==move) { | |
132 | debug("trying to move to same, you should never see this"); | |
133 | return; | |
134 | } | |
135 | ||
136 | var from = get_plid(move); | |
137 | var topos = get_plpos(to); | |
138 | if(from<0 || topos == null || topos == "" ) { | |
139 | debug("Missing id on to or from!"); | |
140 | } | |
141 | send_command("playlist=move&from=" + from + "&to=" + topos, moved_plitem); | |
142 | } | |
143 | ||
144 | /* cut's of elements at the end of playlist */ | |
145 | function playlist_resize(size) { | |
146 | if(pagination.max>0&&pagination.pages>1) { | |
147 | if(pagination.page==pagination.pages-1 && size%pagination.max!=0 ) { | |
148 | remove_children_after(playlist_element, size%pagination.max); | |
149 | } | |
150 | } | |
151 | else { | |
152 | remove_children_after(playlist_element, size); | |
153 | } | |
154 | } | |
155 | ||
156 | function select_playing_song() { | |
157 | var new_p = document.getElementById("plitem_" + playing.id); | |
158 | if(playing.show_node) { | |
159 | if(playing.show_node==new_p) // same node | |
160 | return; | |
161 | apply_border_style_to_children(playing.show_node, "none"); | |
162 | playing.show_node.removeAttribute("playing"); | |
163 | playing.show_node = null; | |
164 | } | |
165 | if(new_p) { | |
166 | apply_border_style_to_children(new_p, PLAYLIST_PLAYING_STYLE); | |
167 | new_p.setAttribute("playing", "i"); | |
168 | playing.show_node = new_p; | |
169 | } | |
170 | ||
171 | } | |
172 | ||
173 | /* not really lazy, but it needs a name */ | |
174 | function get_lazy_info(need_info) { | |
175 | var ids = ""; | |
176 | var start_id=-1, last_id=-1, id; | |
177 | for(id in need_info) { | |
178 | if(start_id<0) { | |
179 | start_id = last_id = id; | |
180 | } | |
181 | else if(last_id==id-1) { | |
182 | last_id = id; | |
183 | } | |
184 | else { | |
185 | ids = add_range(ids, start_id, (start_id==last_id?false:last_id)); | |
186 | start_id = last_id = id; | |
187 | } | |
188 | } | |
189 | ids = add_range(ids, start_id, (start_id==last_id?false:last_id)); | |
190 | ||
191 | if(ids.length>0) { | |
192 | need_info_arr = need_info; | |
193 | /* get missing info and don't get plchanges */ | |
194 | send_command("playlist=info", get_lazy_info_cb, LANG.WAIT_UPDATING_PL, true, "ids=" + encodeURIComponent(ids), true); | |
195 | } | |
196 | } | |
197 | ||
198 | function get_lazy_info_cb(res) { | |
199 | ||
200 | var node,id,info; | |
201 | var ple = pl_entries; | |
202 | ||
203 | var need_info = need_info_arr; | |
204 | need_info_arr = null; | |
205 | if(need_info==null) { | |
206 | //debug("get lazy info cb called, but no need_info array available"); | |
207 | /* FIXME: we have a potential race condition here | |
208 | (may get several results, but only one of them is the one we need and or can use) */ | |
209 | return; | |
210 | } | |
211 | ||
212 | if(!res) { | |
213 | show_status_bar(LANG.E_INVALID_RESULT); | |
214 | hide_status_bar(STATUS_DEFAULT_TIMEOUT); | |
215 | return; | |
216 | } | |
217 | show_status_bar(LANG.WAIT_UPDATING_PL); | |
218 | ||
219 | /* todo: hide when more than 500 changes */ | |
220 | var length = res.length; | |
221 | var plength = ple.length; | |
222 | for(var i=0; i<length; i++) { | |
223 | info = res[i]; | |
224 | var res_id = info.Id; | |
225 | id = false; | |
226 | node = need_info[res_id]; | |
227 | if(node) { | |
228 | info = res[i]; | |
229 | for(var j=1; j<plength;j++) { | |
230 | var val = info[ple[j]]; | |
231 | ||
232 | if(val) { | |
233 | if(ple[j]=="Time") | |
234 | val = convert_minsec(val); | |
235 | } | |
236 | else { | |
237 | if(ple[j]=="Title") { | |
238 | val = info["file"]; | |
239 | val = val.substring(val.lastIndexOf(DIR_SEPARATOR)+1); | |
240 | } | |
241 | else { | |
242 | val = ""; | |
243 | } | |
244 | } | |
245 | if(val.length>29) { | |
246 | node.childNodes[j].title = val; | |
247 | val = val.substring(0,27) + ".."; | |
248 | } | |
249 | else if(node.childNodes[j].title) { | |
250 | node.childNodes[j].removeAttribute("title"); | |
251 | } | |
252 | ||
253 | if(node.childNodes[j].hasChildNodes()) | |
254 | node.childNodes[j].childNodes[0].nodeValue = val; | |
255 | else node.childNodes[j].appendChild(create_txt(val)); | |
256 | } | |
257 | } | |
258 | } | |
259 | hide_status_bar(); | |
260 | ||
261 | if(browser_is_konqueror()) { | |
262 | playlist_element.className = "pltemp"; | |
263 | setTimeout(cclass_for_konqueror, 1); | |
264 | } | |
265 | } | |
266 | ||
267 | /* see bug #46 */ | |
268 | function cclass_for_konqueror() { | |
269 | playlist_element.className = ""; | |
270 | } | |
271 | ||
272 | function pl_selection_changed(sel) { | |
273 | if(sel!=last_pl_selected) { | |
274 | last_pl_selected = sel; | |
275 | document.getElementById('crop_items_button').title = sel?LANG.CROP_SELECTION:LANG.CLEAR_PLAYLIST; | |
276 | } | |
277 | } | |
278 | ||
279 | function plchanges_handler3(list, size) { | |
280 | if(!list||!list.length||list.length<=0) | |
281 | return; | |
282 | var cont = playlist_element; | |
283 | var df = create_fragment(); // temporary storage until we end | |
284 | var buf = create_fragment(); // for appending | |
285 | var i=0; | |
286 | var id; | |
287 | var plid; | |
288 | var pointer = null; // working point in playlist | |
289 | var cursor = null; // temporary point in playlist to make get from doc more effective | |
290 | var need_info = new Array(); | |
291 | var count = 0; | |
292 | ||
293 | /* returns the id of the next item in the list */ | |
294 | function _gn_id() { | |
295 | if(i+1<list.length) | |
296 | return "plitem_" + list[i+1]["Id"]; | |
297 | else return null; | |
298 | } | |
299 | /* checks if it is in cache */ | |
300 | function _get_from_df(id) { | |
301 | var cf = df.childNodes; | |
302 | for (var j=0; j<cf.length; j++) { | |
303 | if(cf[j].id&&cf[j].id==id) { | |
304 | return df.removeChild(cf[j]); | |
305 | } | |
306 | } | |
307 | return null; | |
308 | } | |
309 | ||
310 | function _get_from_doc(id) { | |
311 | /* document.getElementById seems slow on large lists, | |
312 | and there are a few assumptions we can make.. */ | |
313 | if(!cursor) | |
314 | cursor = pointer.nextSibling; | |
315 | var start_point = cursor; | |
316 | var stop_at = false; | |
317 | while(cursor) { | |
318 | if(cursor.id == id) { | |
319 | var ret = cursor; | |
320 | cursor = cursor.nextSibling; | |
321 | return cont.removeChild(ret); | |
322 | } | |
323 | cursor = cursor.nextSibling; | |
324 | if(!cursor&&start_point) { | |
325 | if(start_point!=pointer.nextSibling) { | |
326 | stop_at = start_point; | |
327 | start_point = false; | |
328 | cursor = pointer.nextSibling; | |
329 | } | |
330 | } | |
331 | if(stop_at == cursor) | |
332 | break; | |
333 | } | |
334 | return null; | |
335 | } | |
336 | ||
337 | /* create a row */ | |
338 | function _create_row(id) { | |
339 | /* wow, what a mess.... */ | |
340 | n = create_lazy_pl_row(list[i], "plitem_" + id); | |
341 | need_info[id] = n; | |
342 | return n; | |
343 | } | |
344 | ||
345 | function _update_current_row(id) { | |
346 | pointer.id = "plitem_" + id; | |
347 | need_info[id] = pointer; | |
348 | } | |
349 | ||
350 | function _get_from_df_or_create(id) { | |
351 | var n = _get_from_df("plitem_" + id); | |
352 | if(!n) n = _create_row(id); | |
353 | return n; | |
354 | } | |
355 | ||
356 | var changes_length = list.length; | |
357 | var changes_start = parseInt(list[0]["cpos"]); | |
358 | var changes_end = parseInt(list[list.length-1]['cpos']); | |
359 | var pagination_start = pagination.max * pagination.page; | |
360 | var pagination_end = pagination.max + pagination_start; | |
361 | var start_pos = 0; | |
362 | ||
363 | var pagination_switched_page = pagination.need_update; | |
364 | ||
365 | if(pagination.max==0) { | |
366 | start_pos = changes_start; | |
367 | } | |
368 | else if(changes_start<=pagination_start&&changes_end>=pagination_start) { | |
369 | i = pagination_start - changes_start; | |
370 | } | |
371 | else if(changes_start<pagination_end) { | |
372 | i = 0; | |
373 | start_pos = changes_start - pagination_start; | |
374 | } | |
375 | else { // outside range | |
376 | return; // let's hope we can just return... | |
377 | } | |
378 | ||
379 | if(start_pos<cont.childNodes.length&&start_pos>=0) { | |
380 | pointer = cont.childNodes[start_pos]; | |
381 | } | |
382 | else if(pointer==null) { | |
383 | pointer = _create_row(list[0]["Id"]); | |
384 | cont.appendChild(pointer); | |
385 | } | |
386 | ||
387 | if(start_pos==0) { // make sure there are no-one before us... | |
388 | if(pointer.previousSibling) { | |
389 | // todo obviously (if needed) | |
390 | debug("let me know if you ever see this message (NTS, plchanges_handler)"); | |
391 | } | |
392 | } | |
393 | ||
394 | var append = false; | |
395 | var length = list.length; | |
396 | var n, nid; | |
397 | var max = pagination.max || Number.MAX_VALUE; | |
398 | ||
399 | var _insert_before = insert_before; | |
400 | var _replace_node = replace_node; | |
401 | ||
402 | for(; i < length && start_pos++ < max; i++) { | |
403 | id = list[i]["Id"]; | |
404 | if(append) { | |
405 | n = _get_from_df_or_create(id) | |
406 | buf.appendChild(n); | |
407 | continue; | |
408 | } | |
409 | plid = "plitem_" + id; | |
410 | ||
411 | // if it's a page switch everything will have to be updated | |
412 | if(pagination_switched_page) { | |
413 | _update_current_row(id); | |
414 | } | |
415 | else if(pointer.id!=plid) { | |
416 | nid = _gn_id(); | |
417 | n = _get_from_df(plid); | |
418 | /* if n is found in df it has been removed, but wants back in */ | |
419 | if(n||nid==null||pointer.id==nid) { | |
420 | if(!n) | |
421 | n = _get_from_doc(plid); | |
422 | if(!n) | |
423 | n = _create_row(id); | |
424 | _insert_before(n, pointer); | |
425 | //debug("insert"); | |
426 | } | |
427 | else { | |
428 | if(!n) | |
429 | n = _get_from_doc(plid); | |
430 | if(!n) | |
431 | n = _create_row(id); | |
432 | _replace_node(n,pointer); | |
433 | df.appendChild(pointer); | |
434 | //debug("replace"); | |
435 | } | |
436 | pointer = n; | |
437 | } | |
438 | if(pointer.nextSibling) | |
439 | pointer = pointer.nextSibling; | |
440 | else | |
441 | append = true; | |
442 | } | |
443 | ||
444 | if(buf.hasChildNodes()) | |
445 | cont.appendChild(buf); | |
446 | if(need_info.length>0) | |
447 | get_lazy_info(need_info); | |
448 | ||
449 | playlist_resize(size); | |
450 | update_node_positions2(cont); | |
451 | select_playing_song(); | |
452 | ||
453 | // must be called last | |
454 | if(pagination_switched_page) | |
455 | pagination_post_pageswitch(); | |
456 | } | |
457 | ||
458 | function update_node_positions2(container) { | |
459 | var node = container.firstChild; | |
460 | var found_diff = false; | |
461 | var i = pagination.max * pagination.page; | |
462 | while(node) { | |
463 | if(found_diff) { | |
464 | set_pl_position(node, i++); | |
465 | node = node.nextSibling; | |
466 | } | |
467 | else { | |
468 | if(get_plpos(node)==i) { | |
469 | node = node.nextSibling; | |
470 | i++; | |
471 | } | |
472 | else { | |
473 | found_diff = true; | |
474 | } | |
475 | } | |
476 | } | |
477 | return i; | |
478 | } | |
479 | ||
480 | function pagination_init() { | |
481 | ||
482 | pagination.following = null; // set to true/false in pagination_is_following | |
483 | ||
484 | /* these values shouldn't be hard-coded, but they are */ | |
485 | pagination.left = 50; | |
486 | pagination.width = 680; | |
487 | ||
488 | pagination.scroll_id = false; | |
489 | pagination.scroll_left = false; | |
490 | ||
491 | pagination.follow_button = document.getElementById("pagination_follow_current"); | |
492 | pagination.scroll_to_pos_after_switch = false; | |
493 | pagination_update_follow(); | |
494 | } | |
495 | ||
496 | /* should only be called when the size of the list has been changed and pages no longer fit*/ | |
497 | function pagination_update_list(size) { | |
498 | if(pagination.max<=0) | |
499 | return; | |
500 | var l = pagination.list; | |
501 | var npages = Math.ceil(size/pagination.max); // number of pages | |
502 | var cpages = pagination.pages; // current number of pages | |
503 | var cpage = pagination.page; | |
504 | ||
505 | while(npages>cpages) { | |
506 | var n = add_li(l, cpages+1); | |
507 | n.setAttribute("page", cpages++); | |
508 | } | |
509 | while(npages<cpages) { | |
510 | remove_node(l.lastChild); | |
511 | cpages--; | |
512 | } | |
513 | ||
514 | pagination.container.style.display = cpages>1?"block":""; | |
515 | ||
516 | pagination.pages = cpages; | |
517 | /* if we have switched page it needs update */ | |
518 | if(cpage>=cpages) { | |
519 | cpage = cpages - 1; | |
520 | } | |
521 | pagination_update_current_page(cpage); | |
522 | } | |
523 | ||
524 | /* c: new page number */ | |
525 | function pagination_update_current_page(c) { | |
526 | if(pagination.max<=0) | |
527 | return; | |
528 | var p = pagination.list.firstChild; | |
529 | ||
530 | if(pagination.cpage&&pagination.cpage.hasAttribute("cpage")) | |
531 | pagination.cpage.removeAttribute("cpage"); | |
532 | ||
533 | while(p) { | |
534 | if(p.getAttribute("page")==c) { | |
535 | scrollIntoView(p); | |
536 | p.setAttribute("cpage", "1"); | |
537 | break; | |
538 | } | |
539 | p = p.nextSibling; | |
540 | } | |
541 | pagination.cpage = p; | |
542 | pagination.page = c; | |
543 | } | |
544 | ||
545 | function pagination_fetch_current_page() { | |
546 | playing.pl_version = -1; | |
547 | pagination.need_update = true; | |
548 | reschedule_update_now(); | |
549 | } | |
550 | ||
551 | function pagination_change_page(e, page) { | |
552 | if(e!=null&&e.target.hasAttribute("page")) { | |
553 | pagination.page = parseInt(e.target.getAttribute("page")); | |
554 | } | |
555 | else if(typeof(page)!='undefined') { | |
556 | pagination.page = page; | |
557 | } | |
558 | else { | |
559 | return; | |
560 | } | |
561 | ||
562 | pagination_update_current_page(pagination.page); | |
563 | pagination_fetch_current_page(); | |
564 | unselect_all_nodes(playlist_element); | |
565 | } | |
566 | ||
567 | function pagination_scroll_view(e) { | |
568 | var x = e.pageX - pagination.left; | |
569 | var left = false; | |
570 | var abort = true; | |
571 | ||
572 | if(x>pagination.width-20) { | |
573 | abort = false; | |
574 | } | |
575 | else if(x<20&&pagination.list.scrollLeft>0) { | |
576 | abort = false; | |
577 | left = true; | |
578 | } | |
579 | ||
580 | if(!pagination.scroll_id&&!abort) { | |
581 | pagination_scroll_real(left); | |
582 | } | |
583 | else if(pagination.scroll_id&&abort) { | |
584 | pagination_scroll_stop(); | |
585 | } | |
586 | ||
587 | stop_event(e); | |
588 | } | |
589 | ||
590 | function pagination_scroll_stop(e) { | |
591 | ||
592 | if(e && e.relatedTarget && (e.relatedTarget.id=="pagination_list"||e.relatedTarget.parentNode.id=="pagination_list"||typeof(e.relatedTarget.page)!='undefined')) | |
593 | return; | |
594 | ||
595 | if(pagination.scroll_id) { | |
596 | clearTimeout(pagination.scroll_id); | |
597 | pagination.scroll_id = false; | |
598 | } | |
599 | } | |
600 | ||
601 | function pagination_is_following() { | |
602 | if(pagination.following == null) { | |
603 | var f = setting_get("follow_playing"); | |
604 | if(f&&parseInt(f)) | |
605 | pagination.following = true; | |
606 | else pagination.following = false; | |
607 | } | |
608 | return pagination.following; | |
609 | } | |
610 | ||
611 | function pagination_set_following(follow) { | |
612 | setting_set("follow_playing", (follow?"1":"0")); | |
613 | pagination.following = follow; | |
614 | pagination_update_follow(); | |
615 | } | |
616 | ||
617 | function pagination_toggle_following() { | |
618 | pagination_set_following(!pagination_is_following()); | |
619 | } | |
620 | ||
621 | function pagination_update_follow() { | |
622 | if(!pagination.follow_button) | |
623 | return; | |
624 | if(pagination_is_following()) { | |
625 | pagination.follow_button.src = IMAGE.PAGINATION_FOLLOW; | |
626 | pagination.follow_button.title = LANG.PAGINATION_FOLLOW; | |
627 | } | |
628 | else { | |
629 | pagination.follow_button.src = IMAGE.PAGINATION_NOFOLLOW; | |
630 | pagination.follow_button.title =LANG.PAGINATION_NOFOLLOW; | |
631 | } | |
632 | } | |
633 | ||
634 | /** left or right */ | |
635 | function pagination_scroll_real(left) { | |
636 | var l = pagination.list; | |
637 | var adjust = 0; | |
638 | ||
639 | if(left) { | |
640 | if(l.scrollLeft>0) | |
641 | adjust = -10; | |
642 | else return; | |
643 | } | |
644 | else { | |
645 | adjust = 10; | |
646 | } | |
647 | try { | |
648 | l.scrollLeft += adjust; | |
649 | if(pagination.scroll_id) | |
650 | clearTimeout(pagination.scroll_id); | |
651 | pagination.scroll_id = setTimeout(pagination_scroll_real, 50, left); | |
652 | }catch(e) {debug(e.message);} | |
653 | } | |
654 | ||
655 | function pagination_post_pageswitch() { | |
656 | pagination.need_update = false; | |
657 | if(pagination.scroll_to_pos_after_switch!=false) { | |
658 | var n = playlist_scroll_to_pos_real(pagination.scroll_to_pos_after_switch); | |
659 | pagination.scroll_to_pos_after_switch = false; | |
660 | if(n) { | |
661 | unselect_all_nodes(playlist_element); | |
662 | select_node(n); | |
663 | } | |
664 | } | |
665 | else if(pagination_is_following()&&playing.show_node) { | |
666 | playlist_scroll_to_pos_real(playing.pos); | |
667 | } | |
668 | } | |
669 | ||
670 | ||
671 | /* Returns false if have to switch page, true otherwise */ | |
672 | function playlist_scroll_to_playing() { | |
673 | return playlist_scroll_to_pos(playing.pos); | |
674 | } | |
675 | ||
676 | /* set select to true if all other nodes should be unselected and the right node selected */ | |
677 | function playlist_scroll_to_pos(pos, select) { | |
678 | if(pagination.max>0) { | |
679 | if(pos<0) pos = 0; | |
680 | var page = Math.floor(pos/pagination.max); | |
681 | if(page!=pagination.page) { | |
682 | pagination_change_page(null, page); | |
683 | if(select) | |
684 | pagination.scroll_to_pos_after_switch = pos; | |
685 | return false; // selecting handled in pagination_post_pageswitch | |
686 | } | |
687 | } | |
688 | var n = playlist_scroll_to_pos_real(pos); | |
689 | if(select) { | |
690 | unselect_all_nodes(playlist_element); | |
691 | select_node(n); | |
692 | } | |
693 | return true; | |
694 | } | |
695 | ||
696 | function playlist_scroll_to_pos_real(pos) { | |
697 | if(pagination.max>0) { | |
698 | pos = pos%pagination.max | |
699 | } | |
700 | ||
701 | if(pos<0) { | |
702 | } | |
703 | else if(pos<playlist_element.childNodes.length) { | |
704 | var n = playlist_element.childNodes[pos]; | |
705 | window.scrollTo(0,n.offsetTop -20); | |
706 | return n; | |
707 | } | |
708 | else if(playlist_element.childNodes.length) {//if something in playlist, nag about it | |
709 | debug("scroll to node request outside range"); | |
710 | } | |
711 | return null; | |
712 | } | |
713 | ||
714 | function get_pl_selection_range(invert) { | |
715 | var c = playlist_element.childNodes; | |
716 | var sel = ""; | |
717 | var pagination_add = invert&&pagination.max>0; | |
718 | ||
719 | /* if we have pagination and not on page one, we need to add everything up until this page first */ | |
720 | if(pagination_add&&pagination.page>0) { | |
721 | sel = add_range(sel, 0, pagination.max * pagination.page -1); | |
722 | } | |
723 | ||
724 | var tmp_start = null; | |
725 | var tmp_stop = null; | |
726 | var length = c.length; | |
727 | for(var i=0; i<length; i++) { | |
728 | var selected = is_node_selected(c[i]); | |
729 | if(invert) | |
730 | selected = !selected; | |
731 | if(selected) { | |
732 | if(!tmp_start) | |
733 | tmp_start = c[i]; | |
734 | else tmp_stop = c[i]; | |
735 | } | |
736 | else if(tmp_start) { | |
737 | tmp_start = get_plpos(tmp_start); | |
738 | if(tmp_stop) | |
739 | tmp_stop = get_plpos(tmp_stop); | |
740 | sel = add_range(sel, tmp_start, tmp_stop); | |
741 | tmp_start = null; | |
742 | tmp_stop = null; | |
743 | } | |
744 | } | |
745 | if(tmp_start) { | |
746 | tmp_start = get_plpos(tmp_start); | |
747 | // todo: what if not proper last node | |
748 | if(tmp_stop) | |
749 | tmp_stop = get_plpos(tmp_stop); | |
750 | sel = add_range(sel, tmp_start, tmp_stop); | |
751 | } | |
752 | ||
753 | // add after this page | |
754 | if(pagination_add&&pagination.page+1<pagination.pages) { | |
755 | sel = add_range(sel, (pagination.page+1)*pagination.max, playing.pl_size-1); | |
756 | } | |
757 | return sel; | |
758 | } | |
759 | ||
760 | function playlist_dblclick(elem, e) { | |
761 | var id = get_plid(elem); | |
762 | if(id>=0) { | |
763 | var cmd = "act=play&id=" + get_plid(elem); | |
764 | send_command(cmd); | |
765 | } | |
766 | } | |
767 | ||
768 | function playlist_add_button(e) { | |
769 | if(!playlist_add_popup) { | |
770 | playlist_add_popup = playlist_add_create_content( | |
771 | document.getElementById("playlist_add")); | |
772 | } | |
773 | stop_event(e); | |
774 | playlist_add_popup.show(); | |
775 | } | |
776 | ||
777 | function playlist_save_button(e) { | |
778 | if(!playlist_save_popup) { | |
779 | playlist_save_popup = playlist_save_create_content( | |
780 | document.getElementById("playlist_save")); | |
781 | } | |
782 | stop_event(e); | |
783 | playlist_save_popup.show(); | |
784 | } | |
785 | ||
786 | /* these functions should be merged somehow */ | |
787 | function playlist_add_create_content(padd) { | |
788 | var cats = new Array(LANG.BY_URL); //, "From file", "Text"); | |
789 | var c = create_fragment(); | |
790 | var ul = create_node("ul"); | |
791 | ul.className = "playlist_popup"; | |
792 | c.appendChild(ul); | |
793 | var li; | |
794 | for(var i=0; i < cats.length; i++) { | |
795 | li = add_li(ul, cats[i]); | |
796 | li.className = "playlist_popup"; | |
797 | } | |
798 | li = add_li(ul, LANG.CLOSE); | |
799 | li.className = "playlist_popup"; | |
800 | add_listener(li, "click", playlist_add_close); | |
801 | var d = create_node("div"); | |
802 | c.appendChild(d); | |
803 | ||
804 | var tmp = create_node("input", "playlist_add_url"); | |
805 | add_listener(tmp, "keydown", playlist_add_by_url); | |
806 | d.appendChild(tmp); | |
807 | ||
808 | tmp = create_node("span"); | |
809 | d.appendChild(tmp); | |
810 | tmp.className = "playlist_popup"; | |
811 | tmp.appendChild(create_txt(" Add")); | |
812 | add_listener(tmp, "click", playlist_add_by_url); | |
813 | ||
814 | var pop = new Popup(padd, c); | |
815 | pop.popup.style.marginLeft = "-140px"; | |
816 | /* don't let the click get anywhere else either */ | |
817 | add_listener(pop.popup, "click", stop_event); | |
818 | return pop; | |
819 | } | |
820 | ||
821 | function playlist_save_create_content(psave) { | |
822 | var c = create_fragment(); | |
823 | var tmp = create_node("p"); | |
824 | tmp.className = "nomargin"; | |
825 | tmp.appendChild(create_txt(LANG.PL_SAVE_AS)); | |
826 | var close = create_node("span"); | |
827 | add_listener(close, "click", playlist_save_close); | |
828 | close.appendChild(create_txt(LANG.CLOSE)); | |
829 | close.className = "playlist_popup"; | |
830 | tmp.appendChild(close); | |
831 | tmp.appendChild(create_node("br")); | |
832 | c.appendChild(tmp); | |
833 | tmp = create_node("input", "playlist_save_box"); | |
834 | add_listener(tmp, "keydown", playlist_save_listener); | |
835 | c.appendChild(tmp); | |
836 | tmp = create_node("span"); | |
837 | tmp.appendChild(create_txt(" " + LANG.SAVE)); | |
838 | tmp.className = "playlist_popup"; | |
839 | add_listener(tmp, "click", playlist_save_listener); | |
840 | c.appendChild(tmp); | |
841 | ||
842 | var pop = new Popup(psave, c); | |
843 | pop.popup.style.marginLeft = "-140px"; | |
844 | /* don't let the click get anywhere else either */ | |
845 | add_listener(pop.popup, "click", stop_event); | |
846 | return pop; | |
847 | } | |
848 | ||
849 | function playlist_add_by_url(e) { | |
850 | stop_propagation(e); | |
851 | if((e.type=="keydown"&&e.keyCode==RETURN_KEY_CODE)||e.type=="click") { | |
852 | stop_event(e); | |
853 | var p = document.getElementById("playlist_add_url"); | |
854 | var url = p.value; | |
855 | url = url.trim(); | |
856 | if(url.length>6) { | |
857 | send_command("playlist_add_url=" + encodeURIComponent(url), | |
858 | playlist_add_by_url_cb, LANG.WAIT_ADDING_PL); | |
859 | p.value = ""; | |
860 | playlist_add_close(); | |
861 | } | |
862 | } | |
863 | } | |
864 | ||
865 | function playlist_save_listener(e) { | |
866 | stop_propagation(e); | |
867 | if((e.type=="keydown"&&e.keyCode==RETURN_KEY_CODE)||e.type=="click") { | |
868 | stop_event(e); | |
869 | var p = document.getElementById("playlist_save_box"); | |
870 | var name = p.value; | |
871 | name = name.trim(); | |
872 | if(name.length>0) { | |
873 | send_command("playlist_save=" + encodeURIComponent(name), playlist_save_cb, LANG.PL_SAVING); | |
874 | p.value = ""; | |
875 | playlist_save_popup.hide(); | |
876 | } | |
877 | } | |
878 | } | |
879 | ||
880 | function playlist_add_by_url_cb(result) { | |
881 | if(result=="failed") { | |
882 | show_status_bar(LANG.E_FAILED_ADD_PL); | |
883 | hide_status_bar(STATUS_DEFAULT_TIMEOUT); | |
884 | } | |
885 | else { | |
886 | } | |
887 | } | |
888 | ||
889 | function playlist_save_cb(result) { | |
890 | if(result=="failed") { | |
891 | show_status_bar(LANG.E_FAILED_SAVE_PL); | |
892 | hide_status_bar(STATUS_DEFAULT_TIMEOUT); | |
893 | } | |
894 | } | |
895 | ||
896 | function playlist_add_close(e) { | |
897 | if(e) | |
898 | stop_event(e); | |
899 | if(playlist_add_popup) | |
900 | playlist_add_popup.hide(); | |
901 | } | |
902 | function playlist_save_close(e) { | |
903 | if(e) | |
904 | stop_event(e); | |
905 | if(playlist_save_popup) | |
906 | playlist_save_popup.hide(); | |
907 | } |