]> Joshua Wise's Git repositories - patchfork.git/blob - std/toolkit.js
Update support for Amazon coverart grabbing (patch from Václav Nováček <waclaw66...
[patchfork.git] / std / toolkit.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
20 /**
21  * Why reinvent the wheel when you can make a hexadecagon instead -- Me
22  * 
23  * -- OR --
24  * 
25  * Reinventing the wheel to run myself over -- FOB
26  */
27
28 var moveables = new Array(); 
29 var move_idx = -1;
30
31 var sliders = new Array();
32 var slider_idx = -1;
33
34 var overlay = new Array(); 
35 var overlay_adjust = 100; // px
36 var open_overlay_idx = -1;
37 var overlay_time = 5;
38 var overlay_hide_on_resize = true; // hide content on resize?
39
40 var xpath_queries;
41
42 function debug(str, force) {
43         
44         /* switch && false to true on release */
45         if(typeof(force)=="undefined" && true) {
46                 return;
47         }
48
49         var d = document.getElementById('debugbox');
50         if(d==null) {
51           d = create_node("div");
52           d.id = "debugbox"; 
53           document.body.appendChild(d);
54         }
55
56         var n = create_node("p", null, str);
57         n.style.padding = "0px";
58         n.style.margin = "0px";
59         d.appendChild(n);
60         try {
61                 scrollIntoView(d.lastChild);
62         }
63         catch (e) {}
64 }
65
66 function get_time() {
67         var d = new Date();
68         return d.getTime();
69 }
70
71 /* evaluates json response and returns object containing information */
72 function evaluate_json(txt) {
73         var obj = new Object();
74
75         /* limit context */
76         obj = eval(txt, obj);
77         return obj;
78 }
79
80 function browser_is_opera() {
81         return window.opera?true:false;
82 }
83 function browser_is_konqueror() {
84         if(navigator.vendor=="KDE")
85                 return true;
86         return false;
87 }
88
89 // replaces rem with ins
90 function replace_node(ins, rem) {
91         return rem.parentNode.replaceChild(ins, rem);
92 }
93 // removes this nodes children
94 function remove_children(what) {
95         if(!what.hasChildNodes)
96                 return null;
97         var buf = create_fragment();
98         while(what.hasChildNodes()) 
99                 buf.appendChild(what.removeChild(what.firstChild));
100         return buf;
101 }
102
103 function remove_node(what) {
104         if(what)
105                 return what.parentNode.removeChild(what);
106         return null;
107 }
108
109 function remove_children_after(container, after) {
110         /* removing elements outside list */
111         var c = container.childNodes;
112         if(after>=c.length)
113                 return;
114         var node = c[parseInt(after)];
115         while(node) {
116                 var t = node.nextSibling;
117                 container.removeChild(node);
118                 node = t;
119         }
120 }
121
122 /* insert 'node' first on 'at' */
123 function insert_first(node, at) {
124         if(at.hasChildNodes())
125                 at.insertBefore(node, at.firstChild);
126         else at.appendChild(node);
127 }
128
129 function insert_before(what, before) {
130         before.parentNode.insertBefore(what, before);
131 }
132
133 function insert_after(what, after) {
134         var p = after.parentNode;
135         if(after.nextSibling)
136                 p.insertBefore(what, after.nextSibling);
137         else p.appendChild(what);
138 }
139
140 function get_node_content(node) {
141
142         if(node.hasChildNodes && node.hasChildNodes())
143                 node = node.childNodes[0];
144
145         if(node.nodeValue) {
146                 return node.nodeValue;
147         }
148         else if(node.textContent) {
149                 return node.textContent;
150         }
151         else if(node.textValue) {
152                 return node.textValue;
153         }
154         else if(node.text) {
155                 return node.text;
156         }
157         else {
158                 return node;
159         }
160 }
161
162 /*Returns content of first node with specified tag
163  */
164 function get_tag(item, tag) {
165         if(item.getElementsByTagName) {
166                 var tmp = item.getElementsByTagName(tag)[0];
167                 if(tmp!=null)
168                         return get_node_content(tmp);
169         }
170         return null;
171 }
172
173 function get_absolute_top(node) {
174         var height = 0; 
175         while(node.offsetParent != null)  {
176                 node = node.offsetParent;
177                 if(node.offsetTop)
178                         height += node.offsetTop;
179         }
180         return height;
181 }
182
183 // returns the absolute distance to start of page
184 function get_absolute_height(node) {
185         return node.offsetTop + get_absolute_top(node); 
186 }
187
188 function get_absolute_left(node) {
189         var left = node.offsetLeft; 
190         while(node.offsetParent != null)  {
191                 node = node.offsetParent;
192                 if(node.offsetLeft) {
193                         left += node.offsetLeft;
194                 }
195         }
196         return left;
197 }
198
199 function EventListener(to, type, func) {
200         this.to = to;
201         this.type = type;
202         this.func = func;
203 }
204
205 EventListener.prototype.register = function() {
206         if( this.to.addEventListener ) {
207                 this.to.addEventListener(this.type, this.func, false);
208         }
209         else if(this.to.attachEvent) {
210                 this.to.attachEvent(this.type, this.func);
211         }
212         else debug("unable to add listener");
213 }
214
215 EventListener.prototype.unregister = function() {
216         if(this.to.removeEventListener) {
217                 this.to.removeEventListener(this.type, this.func, false); 
218         }
219         else if(to.detachEvent) {
220                 this.to.detachEvent(this.type, this.func);
221         }
222         else debug("unable to detach event");
223 }
224
225 /**
226  * Creates a new event listener, register it and return it
227  */
228 function add_listener(to, event_s, func) {
229         var el = new EventListener(to, event_s,func);
230         el.register();
231         return el;
232 }
233
234 function remove_listener(to, event_s, func) {
235         if(to.removeEventListener) {
236                 to.removeEventListener(event_s, func, false); 
237         }
238         else if(to.detachEvent) {
239                 to.detachEvent(event_s, func);
240         }
241         else debug("unable to detach event");
242 }
243
244 /* Get's first real child (e.g. one with an id
245  * from the element specified */
246 function get_first_real_child(from) {
247         from = from.firstChild;
248         while(from.nextSibling) {
249                 if(from.id)
250                         return from;
251                 from = from.nextSibling;
252         }
253         return null;
254 }
255
256 function get_last_real_child(from) {
257         var children = from.childNodes;
258         for(var i=children.length-1; i>=0; i++) {
259                 if(children[i].id) 
260                         return children[i];
261         }
262         return null;
263 }
264
265
266 /*
267  * Operations for creating elements
268  */ 
269 // creates node of type type with id id and content content
270 // returns the node created
271 function create_node(type, id, content) {
272         var node = document.createElement(type);
273         if(id&&id!=null) {
274                 node.id = id;
275                 node.name = id;
276         }
277         if(content&&content!=null) {
278                 if(document.createTextNode) 
279                   node.appendChild(document.createTextNode(content));
280                 else
281                   node.innerHTML = content;
282         }
283         return node;
284 }
285
286 function create_txt(txt) {
287         return document.createTextNode(txt);
288 }
289
290 function create_fragment() {
291         return document.createDocumentFragment();
292 }
293
294 // creates an empty table row with id and
295 // returns it
296 function create_tr(id) {
297         return create_node("tr", id, null);
298 }
299
300 function create_param(name, value) {
301         var p = create_node("param");
302         p.name = name;
303         p.value = value;
304         return p;
305 }
306
307 // add a new TD with id id and content to a tr 
308 function add_td(tr, content, id) {
309         var n = create_node("td", id, content);
310         tr.appendChild(n);
311         return n;
312 }
313
314 function add_li(list, content, id) {
315         var n = create_node("li", id, content);
316         list.appendChild(n);
317         return n;
318 }
319
320 function add_txt(node, txt) {
321         node.appendChild(create_txt(txt));
322 }
323
324 function apply_border_style_to_children(who, style) {
325         var c = who.childNodes;
326         for(var i=0; i<c.length; i++) {
327                 if(c[i].style) {
328                         c[i].style.borderBottom = style;
329                         c[i].style.borderTop = style;
330                 }
331         }
332 }
333
334 function MoveObject(container, on_change, multi_move) {
335         // container, moving, element that's moving, initial position, element that's simulating movement,
336         // function to call if something has been moved and a variable to know if mouse key is down, 
337         // if we should be able to move thigns around, optional doubleclick handler, optional selection change handler,
338         // if we *think* something is selected or not
339         this.container = container;     // container for the elements
340         this.on_change = on_change;     // function to call if something has been moved
341         this.moving = false;            // if we are moving something
342         this.moving_elem = null;        // the elemnt that is moving
343         this.moving_init_pos = null;    // initial position of moving element (pagex,pagey)
344         this.moving_clone = null;       // the clone that is actually moving
345         /* this is for interaction between mousemoving and mousedown */
346         this.possible_move_node = null; // the node the user might try moving
347         this.can_move = true;           // if we are allowed to move anything at all
348         this.double_click_cb = null;    // function to call on doubleclick
349         this.selection_change_cb = null;// function to call when the selection changes (with true or false 
350         this.select_if_no_move = false; // if nothing has moved the node should be selected
351         this.multi_move = multi_move;   // if allow for multiple move we won't do any of the moving and this function should
352                                         // return text that should be placed on the "moving" object
353         this.something_selected = false; // whether something currently is selected
354 }
355
356 /* visual effects 0> moving */
357
358 function setup_node_move(container, on_change, multi_move) {
359         var id = moveables.length;
360         add_listener(container, "mousedown", mouse_down_node);
361         add_listener(container, "mouseup", mouse_up_node);
362         add_listener(container, "mousemove", move_node);
363         container.setAttribute("move_id", id);
364         if(!multi_move)
365                 multi_move = false;
366
367         moveables[id] = new MoveObject(container, on_change, multi_move);
368         return id;
369 }
370
371 function add_move_doubleclick(id, func) {
372         moveables[id].double_click_cb = func;
373 }
374
375 function set_moveable(id, moveable) {
376         moveables[id].can_move = moveable;
377 }
378
379 function set_selection_change_handler(id, func) {
380         moveables[id].selection_change_cb = func;
381 }
382
383 /* NodeSelection _ find out if a node is selected */
384 function is_node_selected(node) {
385         return node.hasAttribute&&node.hasAttribute("selected");
386 }
387
388 /* NodeSelection - set whether a node is selectable or not */
389 function set_node_selectable(node, val) {
390         if(val&&node.hasAttribute&&node.hasAttribute("noselect")) {
391                 node.removeAttribute("noselect");
392         }
393         else node.setAttribute("noselect", "true");
394 }
395
396 /* NodeSelection - select node */
397 function select_node(node) {
398         if(node.hasAttribute("noselect"))
399                 return false;
400         if(node.hasAttribute("selected"))
401                 return true;
402
403         node.setAttribute("selected", "1");
404         return true;
405 }
406
407 function unselect_node(node) {
408         if(node.hasAttribute("selected")) {
409                 node.removeAttribute("selected");
410         }
411 }
412
413 function unselect_all_nodes(container) {
414         if(xpath_ok()) {
415                 var nodes = xpath_query(container, ".//*[@selected]");
416                 var n; 
417                 var elems = new Array();
418                 while((n = nodes.iterateNext())) {
419                         elems[elems.length] = n;
420                 }
421                 for(var i=0; i<elems.length; i++) 
422                         unselect_node(elems[i]);
423         }
424         else {
425                 var node = container.childNodes
426                 if(!node)
427                         return;
428                 for(var i=0; i < node.length; i++)  {
429                         if(node[i].hasAttribute("selected"))
430                                 unselect_node(node[i]);
431                 }
432         }
433 }
434
435 /* will check if anything is selected */
436 function selection_anything_selected(container) {
437         if(xpath_ok()) {
438                 var x = xpath_query(container, ".//*[@selected]", XPathResult.ANY_UNORDERED_NODE_TYPE);
439                 return x.singleNodeValue?true:false;
440         }
441         else {
442                 var nodes = container.childNodes
443                 for(var i=0; i < nodes.length; i++)  {
444                         if(node.hasAttribute("selected"))
445                                 return true;
446                 }
447                 return false;
448         }
449         
450 }
451
452 /* Will find the first selected node and set attribute needle
453  *  in needle if it is found before it returns
454  */
455 function find_first_selected_node(container, needle) {
456         if(xpath_ok()&&!needle) {
457                 var x = xpath_query(container, ".//*[@selected]", XPathResult.FIRST_ORDERED_NODE_TYPE);
458                 return x.singleNodeValue;
459         }
460         else {
461                 var nodes = container.childNodes
462                 var length = nodes.length;
463                 for(var i=0; i < length; i++)  {
464                         var node = nodes[i];
465                         if(needle&&needle==node)
466                                 needle.setAttribute("needle", "found");
467                         if(node.hasAttribute&&node.hasAttribute("selected"))
468                                 return node;
469                 }
470                 return null;
471         }
472 }
473
474 /* selects all nodes between the two */
475 function select_range(from, to) {
476         var node = from; 
477         select_node(from);
478         while(node != null && node!=to) {
479                 node = node.nextSibling;
480                 select_node(node);
481         } 
482 }
483
484 /* will return an array of selected elements attribute in container */
485 function get_attribute_from_selected_elems(container, attribute) {
486         var c = container.childNodes;
487         var ret = new Array();
488         var l = c.length;
489         for(var i=0; i<l; i++) {
490                 if(is_node_selected(c[i]) && c[i].hasAttribute(attribute)) {
491                         ret[ret.length] = c[i].getAttribute(attribute);
492                 }
493         }
494         return ret;
495 }
496
497 function mouse_down_node(e) {
498         if(e.button!=0&&e.button!=1)
499                 return;
500         
501         move_idx = get_target_id(e.target);
502
503         if(move_idx<0) 
504                 return;
505         stop_event(e);
506
507         var m = moveables[move_idx];
508         var elem = find_target_node(e.target);
509         if(elem==null)
510                 return;
511         /* move_node will toggle this if true and call start_node_move to initiate moving*/
512         // do not move if it specified not to move
513         if(m.can_move) {
514                 m.moving_init_pos = new Array(e.pageX, e.pageY);
515                 m.possible_move_node = elem;
516         }
517         var something_selected = true;
518         if(e.detail>1) { // we were just here, don't do the other stuff again..
519                 /* double click */
520                 if(m.double_click_cb&&e.detail==2) 
521                         m.double_click_cb(elem, e);
522         }
523         else if(e.ctrlKey||e.metaKey) {
524                 if(is_node_selected(elem)) {
525                         unselect_node(elem);
526                         if(m.selection_change_cb&&m.something_selected)
527                                 something_selected = selection_anything_selected(m.container);
528                 }
529                 else {
530                         select_node(elem);
531                 }
532         }
533         else if (e.shiftKey) {
534                 var sel_node = null; 
535                 
536                 sel_node = find_first_selected_node(m.container, elem);
537                 if(sel_node==null) {
538                         select_node(elem);
539                 }
540                 else {
541                         if(elem.hasAttribute("needle")) {
542                                 select_range(elem, sel_node);
543                                 elem.removeAttribute("needle");
544                         }
545                         else {
546                                 select_range(sel_node, elem);
547                         }
548                 }
549         }
550         else {
551                 if(!is_node_selected(elem)) {
552                         unselect_all_nodes(m.container);
553                         select_node(elem);
554                 }
555                 else {
556                         m.select_if_no_move = true;
557                 }
558         }
559         /* something selected */
560         if(m.selection_change_cb) {
561                 m.selection_change_cb(something_selected);
562                 m.something_selected = something_selected;
563         }
564 }
565
566 function mouse_up_node(e) {
567         if(move_idx<0)
568                 return;
569         var m = moveables[move_idx];
570         if(m.moving) {
571                 stop_node_move(e);
572         }
573         else if(m.select_if_no_move) {
574                 var elem = find_target_node(e.target);
575                 unselect_all_nodes(m.container);
576                 select_node(elem);
577         }
578         m.select_if_no_move = false;
579         m.possible_move_node = null;
580         // safari workaround
581         m.container.className = m.container.className;
582 }
583
584 /* todo; rework to use elem instead of event */
585 function start_node_move(e, elem) {
586         stop_event(e);
587
588         move_idx = get_target_id(e.target);
589
590         if(move_idx<0)
591                 return;
592         if(!moveables[move_idx].can_move)
593                 return;
594
595         var m = moveables[move_idx];
596         var move = find_target_node(e.target);
597         var container = m.container;
598         if(move!=null) {
599                 m.moving = true; // moving 
600                 m.moving_elem = find_target_node(m.possible_move_node); // what
601                 move = m.moving_elem;
602                 m.possible_move_node = null;
603                 var txt = "Moving";
604                 if(m.multi_move) 
605                         txt = m.multi_move();
606                 else if(move.childNodes[1])
607                         txt = move.childNodes[1].textContent; 
608                 else txt = move.childNodes[0].textConten;
609
610                 m.moving_clone = detach_node(move, txt);
611                 set_node_offset(e, m.moving_clone);
612
613                 add_listener(document.body, "mouseup", stop_node_move);
614                 add_listener(document.body, "mousemove", move_node);
615
616                 container.style.cursor = "move";
617         }
618         else move_idx = -1; 
619 }
620
621
622 /* basically the reverse of start */
623 function stop_node_move(e) {
624         if(move_idx<0||!moveables[move_idx].moving)
625                 return;
626
627         var m = moveables[move_idx];
628         m.moving = false;
629         var move = m.moving_elem;
630         var container = m.container;
631         var target = find_target_node(e.target);
632
633         if(m.multi_move) {
634                 /* don't move it if we are moving on top of selection */
635                 if(target&&!is_node_selected(target)) {
636                         m.on_change(null,target);
637                 }
638                 reattach_node(move, null, m.moving_clone, 4); // remove moving node
639         }
640         else if(target!=null&&target!=move) {
641                 /* if first in list or above the one beeing moved, move it up */
642                 var to = null;
643                 if(target==get_first_real_child(container)||target.nextSibling==move) {
644                         to = target;
645                         reattach_node(move, target, m.moving_clone, 1);
646                 }
647                 else if(target.nextSibling!=null) {
648                         /* normally default action */
649                         var attach_at;
650                         to = target;
651                         if(is_moving_up(container, move, target)) {
652                                 attach_at = target;
653                         }
654                         else {
655                                 attach_at = target.nextSibling;
656                         }
657                         reattach_node(move, attach_at, m.moving_clone, 1);
658                 }
659                 else {
660                         /* basically this means we don't know any better */
661                         /* should not happen unless target actually is last in list */
662                         /*to = get_last_real_child(container);
663                         reattach_node(move, container, m[4], 2);*/
664                         to = target;
665                         reattach_node(move, container, m.moving_clone, 2);
666                 }
667
668                 // say we changed
669                 m.on_change(null, to);
670         }
671         else {
672                 reattach_node(move, null, m.moving_clone, 4); // don't move it
673         }
674
675         container.style.cursor = "default";
676
677         remove_listener(document.body, "mouseup", stop_node_move);
678         remove_listener(document.body, "mousemove", move_node); 
679
680         m.moving_elem = null;
681         m.moving_init_pos = null;
682         m.moving_clone = null;
683         move_idx = -1; 
684 }
685
686 function move_node(e) {
687         var id = window.move_idx || -1;
688         var o = 4; // required offset
689         if(id&&id>=0) { 
690                 if(moveables[id].possible_move_node!=null) {
691                         var p = moveables[id].moving_init_pos;
692                         if(Math.abs(p[0]-e.pageX)>=o||Math.abs(p[1]-e.pageY)>o)
693                                 start_node_move(e);
694                 }
695                 if(!moveables[id].moving)
696                         return;
697
698                 stop_event(e);
699                 set_node_offset(e, moveables[id].moving_clone);
700         }
701 }
702
703 function is_moving_up(container, move, target) {
704         var c = container.childNodes;
705         for(var i=0; i<c.length; i++) {
706                 if(move==c[i])
707                         return false;
708                 if(target==c[i])
709                         return true;
710         }
711         debug("Wops, not moving up or down!")
712         return false;
713 }
714
715
716 function detach_node(d, txt) {
717         var rep = create_node("div");
718         
719         rep.style.width = d.offsetWidth/4 + "px";
720         rep.className = "moving_box";
721
722         txt = create_node("p", null, txt);
723         txt.className = "nomargin";
724         rep.appendChild(txt);
725
726         d.setAttribute("old_class", d.className);
727         d.className = "moving";
728
729         document.body.appendChild(rep);
730         return rep;
731 }
732  /* reattach node at specified position (at) with action
733  *  1 => insertBefore
734  *  2 => appendChild
735  *  3 => replaceChild
736  *  4 => dont move
737  */
738 function reattach_node(node, at, clone, action) {
739         node.style.width =""; 
740         node.style.top = "";
741         node.style.position = "";
742         node.className = node.getAttribute("old_class");
743         if(action==1) {
744                 remove_node(node);
745                 at.parentNode.insertBefore(node, at);
746         }
747         else if(action == 2) {
748                 remove_node(node);
749                 at.appendChild(node); 
750         }
751         else if(action == 3) {
752                 remove_node(node);
753                 replace_node(node, at);
754         }
755         else if(action==4)  { 
756         }
757         else {
758                 debug("invalid action in reattach_node");
759         }
760         remove_node(clone);
761 }
762
763 function get_target_id(target) {
764         var t = find_target_node(target);
765         if(t!=null&&t.parentNode&&t.parentNode!=null) 
766                 return t.parentNode.getAttribute("move_id");
767         else return -1;
768 }
769
770 function find_target_node(target) {
771         while(target != null && target.parentNode&&target.parentNode != null) {
772           for(var i=0; i<moveables.length; i++) 
773             if(moveables[i].container==target.parentNode)
774               return target;
775           target = target.parentNode;
776         }
777         return null;
778 }
779
780 /* set's this node to the position in event */
781 function set_node_offset(ev, node) {
782         /* relative positioning:*/
783         var ot = 0; 
784         var ol = 0; 
785         if(node.hasAttribute("ot")&&node.hasAttribute("ol")) {
786                 ot = node.getAttribute("ot");
787                 ol = node.getAttribute("ol");
788         }
789         else {
790                 ot = node.offsetTop; 
791                 ol = node.offsetLeft - 10;
792                 node.setAttribute("ot", ot);
793                 node.setAttribute("ol", ol); 
794         }
795         var h = ev.pageY - ot; 
796         var l = ev.pageX - ol;
797         /* absolute: 
798         var h = ev.pageY - (node.offsetHeight/2);
799         var l = ev.pageX + 10;*/ 
800         node.style.top = h + "px";
801         node.style.left = l + "px";
802         return h;
803 }
804
805 function Slider(sid, main_slider, change, text_area) {
806         this.main_slider = main_slider;
807         this.change_call = change;
808         this.text_area = text_area;
809         this.value = 0;
810         this.moving_pos = 0;
811         this.user_moving = false;
812         this.timer = null;
813         this.timer_last_pos = null;
814         this.sid = sid;
815 }
816
817 Slider.prototype.setup_timer = function() {
818         if(this.timer!=null)
819                 clearTimeout(this.timer);
820         this.timer_last_pos = this.moving_pos;
821         this.timer = setTimeout(this.timer_cb, 250);
822 }
823 Slider.prototype.timer_cb = function() {
824         // user has managed to hold mousepoitner stil
825         if(this.timer_last_pos==this.moving_pos) {
826                 // omg...
827                 var idx = window.slider_idx;
828                 window.slider_send_callback(idx);
829         }
830         else if(this.user_moving) {
831                 this.setup_timer();
832         }
833 }
834
835 /* should be a div */
836 function setup_slider(slider, callback, txt) {
837         var sid = sliders.length;
838         if(txt!=null) {
839                 txt = create_node("p", "slider_txt_" + sid, txt);
840                 txt.className = "slider_txt";
841                 slider.appendChild(txt);
842         }
843         var s = create_node("div");
844         s.className = "slider_main";
845         s.id = "slider_main" + sid;
846         slider.appendChild(s);
847         var pointer = create_node("div", " ");
848         pointer.className = "slider_pointer";
849         pointer.id = "slider_pointer" + sid;
850         s.setAttribute("sliderid", sid);
851         add_listener(s, "mousedown", mouse_down_slider);
852         pointer.style.height = (s.offsetHeight) + "px";
853         s.appendChild(pointer);
854         sliders[sid] = new Slider(sid, slider, callback, txt);
855         set_slider_pos(sid, 0);
856         return sid;
857 }
858
859 function get_slider_txt(sid) {
860         return sliders[sid].text_area;
861 }
862
863 function slider_send_callback(sid) {
864         if(sliders[sid].change_call)
865                 sliders[sid].change_call(sliders[sid].value);
866 }
867
868 function set_slider_pos(sid, pos, force) {
869         var pointer = document.getElementById("slider_pointer" + sid);
870         var s = document.getElementById("slider_main" + sid);
871         if(!force)
872                 force = false;
873         if(pointer==null||s==null) {
874                 debug("no slider pointer||main");
875                 return;
876         }
877
878         if(sliders[sid].user_moving&&!force)
879                 return;
880
881         if(pos>100)
882                 pos=100;
883         if(pos<0)
884                 pos=0;
885
886         if(pos==sliders[sid].value) {
887                 return;
888         }
889
890         sliders[sid].value = pos;
891
892         var dist = (s.offsetWidth * pos) /100
893         if(isNaN(dist)||dist=="NaN")
894                 dist = 0;
895         
896         pointer.style.left =  dist+ "px";
897 }
898
899 function get_slider_pos(sid) {
900         return sliders[sid].value;
901 }
902
903 function mouse_down_slider(e) {
904         var targ = e.target;
905         /* TODO: rewrite test */
906         if(!targ||!targ.hasAttribute||!targ.hasAttribute("sliderid")) {
907                 if(targ) 
908                         targ = targ.parentNode;
909                 // *umpf*
910                 if(!targ||!targ.hasAttribute||!targ.hasAttribute("sliderid")) 
911                         return;
912         }
913         
914         slider_idx = targ.getAttribute("sliderid");
915
916         add_listener(document.body, "mousemove", mouse_move_slider);
917         add_listener(document.body, "mouseup", mouse_up_slider);
918
919         sliders[slider_idx].user_moving = true;
920         sliders[slider_idx].main_slider.setAttribute("slider_moving", "yeahitis");
921
922         mouse_move_slider(e); // lazy
923         //e.stopPropagation();
924
925 }
926
927 function mouse_move_slider(e) {
928         if(slider_idx<0) {
929                 debug("mouse_move_slider should not be called now");
930                 mouse_up_slider(e);
931                 return;
932         }
933         stop_event(e);
934         var left = slider_get_left(e, slider_idx)
935         set_slider_pos(slider_idx, left, true);
936         sliders[slider_idx].moving_pos = left;
937         sliders[slider_idx].setup_timer(sliders[slider_idx].change_call);
938 }
939
940 function mouse_up_slider(e) {
941         if(slider_idx<0)
942                 return;
943
944         // prolly not necessary though
945         clearTimeout(sliders[slider_idx].timer);
946         sliders[slider_idx].timer = null;
947
948         remove_listener(document.body, "mousemove", mouse_move_slider);
949         remove_listener(document.body, "mouseup", mouse_up_slider);
950         sliders[slider_idx].user_moving = false;
951         sliders[slider_idx].main_slider.removeAttribute("slider_moving");
952         slider_send_callback(slider_idx);
953         slider_idx = -1;
954 }
955
956 function slider_get_left(e, sid) {
957         var x = e.pageX - get_absolute_left(sliders[sid].main_slider);
958         x = (x*100)/sliders[sid].main_slider.offsetWidth;
959         x-=3;
960         if(x<0)
961                 x = 0;
962         return x;
963 }
964
965 function OverlayObject(back, sizes, open_callback, close_callback) {
966         this.back = back; // element to put overlay over
967         this.sizes = sizes; // minimum sizes [top, left, min-height, min-width ]
968         this.open_callback = open_callback;
969         this.close_callback = close_callback;
970         this.overlay = null; // the overlay element
971         this.write = null; // write area
972 }
973
974 /* overlay */
975 function setup_overlay(back, sizes, open_callback, close_callback) {
976         var oid = overlay.length;
977         overlay[oid] = new OverlayObject(back, sizes, open_callback, close_callback); 
978         var t = create_node("div", "overlay_" + oid);
979         overlay[oid].overlay = t;
980         t.className = "overlay";
981         t.style.height = overlay_adjust + "px";
982         var img = create_node("img", "overlay_close_" + oid);
983         img.src = IMAGE.CLOSE;
984         img.setAttribute("oid", oid);
985         img.className = "close fakelink";
986         img.title = "Close [Ctrl+Shift+X]";
987         add_listener(img, "click", close_overlay_cb);
988
989         t.appendChild(img);
990
991         document.body.appendChild(t);
992
993         return oid;
994 }
995
996 function get_overlay_write_area(oid) {
997         if(overlay[oid].write==null) {
998                 overlay[oid].write = create_node("div", "overlay_write_area_" + oid);
999                 overlay[oid].overlay.appendChild(overlay[oid].write);
1000
1001         }
1002         return overlay[oid].write;
1003 }
1004
1005 function open_overlay(oid) {
1006         var sizes = overlay[oid].sizes;
1007         var o = overlay[oid].back;
1008         var top = get_absolute_top(o);
1009         if(top<sizes[0])
1010                 top = sizes[0];
1011         var left = get_absolute_left(o);
1012         if(left<sizes[1])
1013                 left = sizes[1];
1014         var height = o.offsetHeight;
1015         if(height<sizes[2])
1016                 height = sizes[2];
1017         var width = o.offsetWidth;
1018         if(width<sizes[3])
1019                 width = sizes[3];
1020
1021         if(overlay_hide_on_resize&&overlay[oid].write)
1022                 overlay[oid].write.style.display = "none";
1023         
1024         var op = overlay[oid].overlay;
1025         open_overlay_idx = oid;
1026         op.style.left = left + "px";
1027         op.style.top = top + "px";
1028         op.style.width = overlay_adjust + "px";
1029         op.style.height = overlay_adjust + "px";
1030
1031         op.style.display = "block";
1032         var hx = 1, wx =1;
1033         if(width>height) 
1034                 wx = width/height;
1035         else 
1036                 hx = height/width;
1037
1038         overlay[oid].close_key = keyboard_register_listener(close_overlay_cb, "x", KEYBOARD_CTRL_KEY|KEYBOARD_SHIFT_KEY, true);
1039
1040         setTimeout(adjust_overlay_size, overlay_time, oid, new Array(overlay_adjust, overlay_adjust), new Array(height, width, hx, wx));
1041 }
1042
1043 function open_overlay_fixed(oid) {
1044         // TODO: find another way to determine these heights
1045         var sizes = new Array(106, 56, 800, 500); 
1046
1047         var height = sizes[3];
1048         var width = sizes[2];
1049         var op = overlay[oid].overlay;
1050         open_overlay_idx = oid;
1051         if(overlay_hide_on_resize&&overlay[oid].write)
1052                 overlay[oid].write.style.display = "none";
1053         
1054         op.style.position = "fixed";
1055
1056         op.style.left = sizes[1] + "px";
1057         op.style.top = sizes[0] + "px";
1058         op.style.width = overlay_adjust + "px";
1059         op.style.height = overlay_adjust + "px";
1060
1061         op.style.display = "block";
1062
1063         /* adjust to browser window */
1064         var x_o = 30;
1065         var w_h = window.innerHeight; 
1066         var w_w = window.innerWidth; 
1067
1068         /* ignore it if unreasonable values.. */
1069         if(w_h&&w_w&&w_h>100&&w_w>100) {
1070                 if(height+sizes[0]+x_o>w_h)
1071                         height = w_h - sizes[0] - x_o;
1072                 if(width+sizes[1]+x_o>w_w)
1073                         width = w_w - sizes[1] - x_o;
1074         }
1075
1076         var hx = 1, wx =1;
1077         if(width>height) 
1078                 wx = width/height;
1079         else 
1080                 hx = height/width;
1081
1082         overlay[oid].close_key = keyboard_register_listener(close_overlay_cb, "x", KEYBOARD_CTRL_KEY|KEYBOARD_SHIFT_KEY, true);
1083
1084         setTimeout(adjust_overlay_size, overlay_time, oid, new Array(overlay_adjust, overlay_adjust), new Array(height, width, hx, wx));
1085 }
1086
1087 function adjust_overlay_size(oid, current, dest) {
1088         var h = current[0] = current[0] + (dest[2]*overlay_adjust);
1089         var w = current[1] = current[1] + (dest[3]*overlay_adjust);
1090         var adjusted = false;
1091
1092         if(h<dest[0]) {
1093                 adjusted = true;
1094         }
1095         else { 
1096                 h = dest[0];
1097         }
1098         if(w<dest[1]) {
1099                 adjusted = true
1100         }
1101         else {
1102                 w = dest[1];
1103         }
1104         h = parseInt(h);
1105         w = parseInt(w);
1106         overlay[oid].overlay.style.height = h + "px";
1107         overlay[oid].overlay.style.width = w + "px";
1108         //debug("h: " + h + ", w: " + w);
1109
1110         if(adjusted) {
1111                 //debug("setting timeout");
1112                 setTimeout(adjust_overlay_size, overlay_time, oid, current, dest);
1113         }
1114         else {
1115                 var height = (overlay[oid].overlay.offsetHeight-20);
1116                 if(overlay[oid].write) {
1117                         if(overlay_hide_on_resize) {
1118                                 overlay[oid].write.style.display = "block"; // kiss
1119                         }
1120                 }
1121                 if(overlay[oid].open_callback) 
1122                         overlay[oid].open_callback(height);
1123         }
1124 }
1125
1126 function close_overlay(oid) {
1127         var o = overlay[oid].overlay;
1128         open_overlay_idx = -1;
1129         o.style.display = "none";
1130         if(overlay[oid].close_key) 
1131                 overlay[oid].close_key = keyboard_remove_listener(overlay[oid].close_key);
1132         if(overlay[oid].close_callback) 
1133                 overlay[oid].close_callback();
1134 }
1135 function close_overlay_cb(e) {
1136         var t = e.target;
1137         if(t&&t.hasAttribute&&t.hasAttribute("oid")) {
1138                 close_overlay(t.getAttribute("oid"));
1139                 stop_event(e);
1140         }
1141         else if(open_overlay_idx>=0) {
1142                 close_overlay(open_overlay_idx);
1143                 stop_event(e);
1144         }
1145         
1146 }
1147
1148 function stop_propagation(e) {
1149         if(e.stopPropagation)
1150                 e.stopPropagation();
1151 }
1152
1153 function stop_event(e) {
1154         if(e) {
1155                 if(e.preventDefault) 
1156                         e.preventDefault();
1157                 if(e.stopPropagation)
1158                         e.stopPropagation();
1159                 if(e.returnValue) 
1160                         e.returnValue = false;
1161         }
1162 }
1163
1164 /* range selection (to put ranges in a "list" */
1165 /* txt: excisting range:
1166  * from: from what number
1167  * to: optional to argument
1168  */
1169 function add_range(txt, from, to) {
1170         if(txt.length>0)
1171                 txt+=";";
1172         txt+=from;
1173         if(to)
1174                 txt+="-" + to;
1175         return txt;
1176 }
1177
1178 function scrollIntoView(elem, top) {
1179         if(!top)
1180                 top = false;
1181         /* seriously though, if you don't support it, don't claim you do!*/
1182         //if(elem.scrollIntoView) {
1183         if(navigator.product&&navigator.product=="Gecko") {
1184                 elem.scrollIntoView(top);
1185         }
1186         else if(elem.parentNode) {
1187                 // TODO: top
1188                 try { 
1189                         elem.parentNode.scrollTop=elem.offsetTop - (top?elem.offsetHeight*2:elem.parentNode.offsetHeight);
1190                 } catch (e) { }
1191         }
1192 }
1193
1194 function setSelectionRange(input, selectionStart, selectionEnd) {
1195   if (input.setSelectionRange) {
1196     input.focus();
1197     input.setSelectionRange(selectionStart, selectionEnd);
1198   }
1199   else if (input.createTextRange) {
1200     var range = input.createTextRange();
1201     range.collapse(true);
1202     range.moveEnd('character', selectionEnd);
1203     range.moveStart('character', selectionStart);
1204     range.select();
1205     range.detach();
1206   }
1207 }
1208 function setCaretToEnd (input) {
1209   setSelectionRange(input, input.value.length, input.value.length);
1210 }
1211 function setCaretToBegin (input) {
1212   setSelectionRange(input, 0, 0);
1213 }
1214 function setCaretToPos (input, pos) {
1215   setSelectionRange(input, pos, pos);
1216 }
1217
1218
1219
1220 String.prototype.trim = function() {
1221         return this.replace(/^\s+|\s+$/g,'');
1222 }
1223
1224 function add_string_with_br(to, str) {
1225         str = str.replace("\r", "").split('\n');
1226         for(var i=0; i<str.length; i++) {
1227                 if(str[i].length>0)
1228                         to.appendChild(create_txt(str[i]));
1229                 to.appendChild(create_node("br"));
1230         }
1231 }
1232
1233 function adjust_opacity_timer(node, current_opacity, dest_opacity, last_time) {
1234         var now = get_time(); 
1235         var time = now;
1236         if(last_time) 
1237                 time -= last_time;
1238         else time = 0;
1239         
1240         time = 100-time;
1241         //debug("time: " + time);
1242         if(time<0) {
1243                 time = 0;
1244                 current_opacity+=0.2;
1245         }
1246         else {
1247                 current_opacity+=0.1;
1248         }
1249
1250         if(current_opacity<dest_opacity) {
1251                 node.style.opacity = current_opacity ;
1252                 setTimeout(adjust_opacity_timer, time, node, current_opacity, dest_opacity, now);
1253         }
1254         else {
1255                 node.style.opacity = dest_opacity ;
1256         }
1257 }
1258
1259 /* what to blink, what color and count, two first arguments are required */
1260 function blink_node(what, color, count) {
1261         if(typeof(count)=='undefined') {
1262                 count = 3;
1263         }
1264         if(count%2==1)
1265                 what.style.backgroundColor = color;
1266         else 
1267                 what.style.backgroundColor = "";
1268         if(count>0) {
1269                 setTimeout(blink_node, 350, what, color, --count);
1270         }
1271 }
1272
1273 /* popup */
1274 /* if content is null, we'll use tabs */
1275 function Popup(point, content) {
1276         this.point = point;
1277         this.content = content;
1278         this.popup = create_node("div");
1279         if(content)
1280                 this.popup.appendChild(content);
1281         this.popup.className = "popup";
1282         this.point.appendChild(this.popup);
1283 }
1284
1285 Popup.prototype.show = function() {
1286         this.popup.style.display = "block";
1287 }
1288 Popup.prototype.hide = function() {
1289         this.popup.style.display = "";
1290 }
1291 Popup.prototype.destroy = function() {
1292         remove_node(this.popup);
1293         this.popup = null;
1294         this.point = null;
1295         this.content = null;
1296 }
1297
1298 /* xpath */
1299 function xpath_init() {
1300         xpath_queries = new Hashtable();
1301 }
1302
1303 /* checks if xpath is available */
1304 function xpath_ok() {
1305         return document.evaluate?true:false;
1306 }
1307
1308 // remember to check with xpath_ok first when using this function
1309 function xpath_query(container, expression, resulttype, nocache_query) {
1310         if(!resulttype)
1311                 resulttype = XPathResult.ANY_TYPE;
1312         if(nocache_query) {
1313                 return document.evaluate(expression, container, null, resulttype, null);
1314         }
1315         else {
1316                 var e = xpath_queries.get(expression);
1317                 if(!e) {
1318                         e = document.createExpression(expression, null);
1319                         xpath_queries.put(expression, e);
1320                 }
1321                 return e.evaluate(container, resulttype, null); 
1322         }
1323 }
1324
1325 function opera_quirk_set_display_none(element, cleanup) {
1326         if(cleanup) {
1327                 element.style.display = "none";
1328                 element.style.visibility = "";
1329         }
1330         else {
1331                 setTimeout(opera_quirk_set_display_none, 10, element, true);
1332                 element.style.visibility = "hidden";
1333         }
1334 }
1335
1336 function createCookie(name,value,days) {
1337         if (days) {
1338                 var date = new Date();
1339                 date.setTime(date.getTime()+(days*24*60*60*1000));
1340                 var expires = "; expires="+date.toGMTString();
1341         }
1342         else var expires = "";
1343         document.cookie = name+"="+value+expires+"; path=/";
1344 }
1345 function readCookie(name) {
1346         var nameEQ = name + "=";
1347         var ca = document.cookie.split(';');
1348         for(var i=0;i < ca.length;i++) {
1349                 var c = ca[i];
1350                 while (c.charAt(0)==' ') c = c.substring(1,c.length);
1351                 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
1352         }
1353         return null;
1354 }
1355 function eraseCookie(name) {
1356         createCookie(name,"",-1);
1357 }
1358
1359 // This function is in the public domain. Feel free to link back to http://jan.moesen.nu/
1360 function sprintf() {
1361         if (!arguments || arguments.length < 1 || !RegExp) {
1362                 return "";
1363         }
1364         var str = arguments[0];
1365         var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X)(.*)/;
1366         var a = b = [], numSubstitutions = 0, numMatches = 0;
1367         while ((a = re.exec(str))) {
1368                 var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];
1369                 var pPrecision = a[5], pType = a[6], rightPart = a[7];
1370                 
1371                 //alert(a + '\n' + [a[0], leftpart, pPad, pJustify, pMinLength, pPrecision);
1372
1373                 numMatches++;
1374                 if (pType == '%') {
1375                         subst = '%';
1376                 }
1377                 else {
1378                         numSubstitutions++;
1379                         if (numSubstitutions >= arguments.length) {
1380                                 alert('Error! Not enough function arguments (' + (arguments.length - 1) + ', excluding the string)\nfor the number of substitution parameters in string (' + numSubstitutions + ' so far).');
1381                         }
1382                         var param = arguments[numSubstitutions];
1383                         var pad = '';
1384                                if (pPad && pPad.substr(0,1) == "'") pad = leftpart.substr(1,1);
1385                           else if (pPad) pad = pPad;
1386                         var justifyRight = true;
1387                                if (pJustify && pJustify === "-") justifyRight = false;
1388                         var minLength = -1;
1389                                if (pMinLength) minLength = parseInt(pMinLength);
1390                         var precision = -1;
1391                                if (pPrecision && pType == 'f') precision = parseInt(pPrecision.substring(1));
1392                         var subst = param;
1393                                if (pType == 'b') subst = parseInt(param).toString(2);
1394                           else if (pType == 'c') subst = String.fromCharCode(parseInt(param));
1395                           else if (pType == 'd') subst = parseInt(param) ? parseInt(param) : 0;
1396                           else if (pType == 'u') subst = Math.abs(param);
1397                           else if (pType == 'f') subst = (precision > -1) ? Math.round(parseFloat(param) * Math.pow(10, precision)) / Math.pow(10, precision): parseFloat(param);
1398                           else if (pType == 'o') subst = parseInt(param).toString(8);
1399                           else if (pType == 's') subst = param;
1400                           else if (pType == 'x') subst = ('' + parseInt(param).toString(16)).toLowerCase();
1401                           else if (pType == 'X') subst = ('' + parseInt(param).toString(16)).toUpperCase();
1402                 }
1403                 str = leftpart + subst + rightPart;
1404         }
1405         return str;
1406 }
1407
1408 /* settings */
1409
1410 function setting_set(name, value) {
1411         var s = readCookie("pf_conf");
1412         
1413         var ns = "";
1414         var set = false;
1415         if(s) {
1416                 s = s.split(":");
1417                 for(var i=0; i< s.length; i++) {
1418                         var tmp = s[i].split("-");
1419                         if(!tmp[0].length)
1420                                 continue;
1421
1422                         if(tmp[0]==name) {
1423                                 ns+=name + "-" + value;
1424                                 set = true;
1425                         }
1426                         else {
1427                                 ns+=s[i];
1428                         }
1429                         ns+=":";
1430                 }
1431         }
1432         if(!set) 
1433                 ns+=name + "-" +value + ":";
1434         
1435         createCookie("pf_conf", ns, 200);
1436
1437         return true;
1438 }
1439
1440 function setting_get(name) {
1441         var val = readCookie("pf_conf");
1442
1443         if(!val||!val.length)
1444                 return null;
1445
1446         val = val.split(":");
1447         for(var i=0; i < val.length; i++) {
1448                 var t = val[i].split("-");
1449                 if(t[0]==name)
1450                         return t[1];
1451         }
1452         return null;
1453 }
This page took 0.201257 seconds and 4 git commands to generate.