1
2
3
4
5
6
7
8
9
10
11
12
13
14 """
15 DOM implements the core of Pjamas-Desktop, providing access to
16 and management of the DOM model of the PyWebkitGtk window.
17 """
18
19 import pyjd
20
21 if pyjd.is_desktop:
22 from pyjamas.Window import onResize, onClosing, onClosed
23 from __pyjamas__ import JS, doc, get_main_frame, wnd
24
25 currentEvent = None
26
27 sCaptureElem = None
28 sEventPreviewStack = []
29
30 listeners = {}
31
32 from pyjamas.ui import Event
33 from pyjamas.ui.Event import (
34 ONBLUR,
35 ONCHANGE,
36 ONCLICK,
37 ONCONTEXTMENU,
38 ONDBLCLICK,
39 ONERROR,
40 ONFOCUS,
41 ONKEYDOWN,
42 ONKEYPRESS,
43 ONKEYUP,
44 ONLOAD,
45 ONLOSECAPTURE,
46 ONMOUSEDOWN,
47 ONMOUSEMOVE,
48 ONMOUSEOUT,
49 ONMOUSEOVER,
50 ONMOUSEUP,
51 ONSCROLL,
52 ONINPUT
53 )
54
55 ELEMENT_NODE = 1
56 TEXT_NODE = 3
57 DOCUMENT_NODE = 9
58
67
68
76
77
78 hack_timer_workaround_bug_button = None
79
80
82 mf = get_main_frame()
83 mf._addWindowEventListener("click", browser_event_cb)
84 mf._addWindowEventListener("change", browser_event_cb)
85 mf._addWindowEventListener("mouseout", browser_event_cb)
86 mf._addWindowEventListener("mousedown", browser_event_cb)
87 mf._addWindowEventListener("mouseup", browser_event_cb)
88 mf._addWindowEventListener("resize", browser_event_cb)
89 mf._addWindowEventListener("keyup", browser_event_cb)
90 mf._addWindowEventListener("keydown", browser_event_cb)
91 mf._addWindowEventListener("keypress", browser_event_cb)
92 mf._addWindowEventListener("mousewheel", browser_event_cb)
93
95 body = doc().getElementsByTagName("body")[0]
96 mf._addEventListener(body, "click", cb)
97 mf._addEventListener(body, "change", cb)
98 mf._addEventListener(body, "mouseout", cb)
99 mf._addEventListener(body, "mousedown", cb)
100 mf._addEventListener(body, "mouseup", cb)
101 mf._addEventListener(body, "mousemove", cb)
102 mf._addEventListener(body, "resize", cb)
103 mf._addEventListener(body, "keyup", cb)
104 mf._addEventListener(body, "keydown", cb)
105 mf._addEventListener(body, "keypress", cb)
106
109
110
112
113 if evt is None:
114 evt = wnd().event
115 else:
116 try:
117 sender = get_main_frame().gobject_wrap(sender)
118 evt = get_main_frame().gobject_wrap(evt)
119 except:
120 pass
121 listener = None
122 curElem = sender
123
124
125 cap = getCaptureElement()
126 listener = get_listener(cap)
127 if cap and (listener is not None):
128
129 dispatchEvent(evt, cap, listener)
130 evt.stopPropagation()
131 return
132
133 while curElem and (get_listener(curElem) is None):
134
135 curElem = getParent(curElem)
136 if curElem and getNodeType(curElem) != 1:
137 curElem = None
138
139 listener = get_listener(curElem)
140 if listener is not None:
141 dispatchEvent(evt, curElem, listener)
142
143
155
156
158 cap = getCaptureElement()
159
160 if cap is None:
161 return
162
163 if eventGetToElement(evt):
164 return
165
166
167
168 setCapture(None)
169 listener = get_listener(cap)
170 if listener is None:
171 return
172
173
174 lcEvent = doc().createEvent('UIEvent')
175 lcEvent.initUIEvent('losecapture', False, False, wnd(), 0)
176 dispatchEvent(lcEvent, cap, listener)
177
178
205
206
215
216
219
220
224
228
229
232
233
239
240
242 if hasattr(elem1, "isSameNode") and hasattr(elem2, "isSameNode"):
243 return elem1.isSameNode(elem2)
244 return elem1 == elem2
245
246
249
250
253
254
257
258
261
262
265
266
269
270
273
274
277
278
281
282
285
286
291
292
295
296
301
302
305
306
309
310
313
314
317
318
321
322
325
326
329
330
332 return createElement("tbody")
333
334
337
338
340 return createElement("textarea")
341
342
345
346
349
350
353
354
357
358
361
362
365
366
369
370
373
374
377
378
380 try:
381 return evt.fromElement
382 except:
383 return None
384
385
387 return evt.which or evt.keyCode or 0
388
389
392
393
396
397
400
401
404
405
407 return event.currentTarget
408
409
412
413
421
422
425
428
429
432
433
436
437
440
441
444
445
448
449
451 left = 0
452 curr = elem
453 while curr.offsetParent:
454 left -= curr.scrollLeft
455 curr = curr.parentNode
456
457 while elem:
458 left += elem.offsetLeft - elem.scrollLeft
459 elem = elem.offsetParent
460
461 return left
462
463
465 top = 0
466 curr = elem
467 while curr.offsetParent:
468 top -= curr.scrollTop
469 curr = curr.parentNode
470
471 while elem:
472 top += elem.offsetTop - elem.scrollTop
473 elem = elem.offsetParent
474
475 return top
476
477
479 attr = getattr(elem, attr)
480 if attr is None:
481 return None
482 return str(attr)
483
484
486 mf = get_main_frame()
487 if not elem.hasAttribute(attr):
488 return str(getattr(elem, mf.mash_attrib(attr)))
489 return str(elem.getAttribute(attr))
490
491
493 mf = get_main_frame()
494 return bool(getattr(elem, mf.mash_attrib(attr)))
495
496
498 if not elem.hasAttribute(attr):
499 return None
500 return bool(elem.getAttribute(attr))
501
502
506
507
509 """
510 Get a child of the DOM element by specifying an index.
511 """
512 count = 0
513 child = elem.firstChild
514 while child:
515 next = child.nextSibling
516 if child.nodeType == 1:
517 if index == count:
518 return child
519 count += 1
520 child = next
521 return None
522
523
525 """
526 Calculate the number of children the given element has. This loops
527 over all the children of that element and counts them.
528 """
529 count = 0
530 child = elem.firstChild
531 while child:
532 if child.nodeType == 1:
533 count += 1
534 child = child.nextSibling
535 return count
536
537
539 """
540 Return the index of the given child in the given parent.
541
542 This performs a linear search.
543 """
544 count = 0
545 child = parent.firstChild
546 while child:
547 if child == toFind:
548 return count
549 if child.nodeType == 1:
550 count += 1
551 child = child.nextSibling
552
553 return -1
554
555
557 """
558 Return the element in the document's DOM tree with the given id.
559 """
560 return doc().getElementById(id)
561
562
564 """
565 See setEventListener() for more information.
566 """
567 return get_listener(element)
568
569 eventbitsmap = {}
570
571
573 """
574 Return which events are currently "sunk" for a given DOM node. See
575 sinkEvents() for more information.
576 """
577 return eventbitsmap.get(element, 0)
578
579
581 child = elem and elem.firstChild
582 while child and child.nodeType != 1:
583 child = child.nextSibling
584 return child
585
586
588 child = elem and elem.lastChild
589 while child and child.nodeType != 1:
590 child = child.previousSibling
591 return child
592
593
595 try:
596 return element and element.innerHtml
597 except:
598 return element and element.innerHTML
599
600
601 -def getInnerText(element):
602
603
604 text = ''
605 child = element.firstChild
606 while child:
607 if child.nodeType == 1:
608 text += getInnerText(child)
609 elif child.nodeValue:
610 text += child.nodeValue
611 child = child.nextSibling
612 return text
613
614
616 return int(getattr(elem, attr))
617
618
620 if not elem.hasAttribute(attr):
621 return None
622 return int(elem.getAttribute(attr))
623
624
627
628
630 sib = elem.previousSibling
631 while sib and sib.nodeType != 1:
632 sib = sib.previousSibling
633 return sib
634
635
637 sib = elem.nextSibling
638 while sib and sib.nodeType != 1:
639 sib = sib.nextSibling
640 return sib
641
642
645
646
648 parent = elem.parentNode
649 if parent is None:
650 return None
651 if getNodeType(parent) != 1:
652 return None
653 return parent
654
655
657 try:
658 if hasattr(elem.style, 'getPropertyValue'):
659 return elem.style.getPropertyValue(mash_name_for_glib(attr))
660 elif hasattr(elem.style, 'getProperty'):
661 return elem.style.getProperty(mash_name_for_glib(attr))
662 return elem.style.getAttribute(attr)
663 except AttributeError:
664 return getattr(elem.style, attr, None)
665
666
668 count = 0
669 child = parent.firstChild
670 before = None
671 while child:
672 if child.nodeType == 1:
673 if (count == index):
674 before = child
675 break
676
677 count += 1
678 child = child.nextSibling
679
680 if before is None:
681 parent.appendChild(toAdd)
682 else:
683 parent.insertBefore(toAdd, before)
684
685
687
689 self.parent = elem
690 self.child = elem.firstChild
691 self.lastChild = None
692
694 if not self.child:
695 raise StopIteration
696 self.lastChild = self.child
697 self.child = getNextSibling(self.child)
698 return self.lastChild
699
702
705
706
708 """
709 Returns an iterator over all the children of the given
710 DOM node.
711 """
712 return IterChildrenClass(elem)
713
714
716
717 - def __init__(self, elem, all_nodes=False):
718 self.parent = elem
719 self.all_nodes = all_nodes
720 if all_nodes:
721 self.child = elem.firstChild
722 else:
723 self.child = getFirstChild(elem)
724 self.lastChild = None
725 self.stack = []
726
728 if not self.child:
729 raise StopIteration
730 self.lastChild = self.child
731 if self.all_nodes:
732 firstChild = self.child.firstChild
733 nextSibling = self.child.nextSibling
734 else:
735 firstChild = getFirstChild(self.child)
736 nextSibling = getNextSibling(self.child)
737 if firstChild is not None:
738 if nextSibling is not None:
739 self.stack.append((nextSibling, self.parent))
740 self.parent = self.child
741 self.child = firstChild
742 elif nextSibling is not None:
743 self.child = nextSibling
744 elif len(self.stack) > 0:
745 (self.child, self.parent) = self.stack.pop()
746 else:
747 self.child = None
748 return self.lastChild
749
752
755
756
758 """
759 Walk an entire subtree of the DOM. This returns an
760 iterator/iterable which performs a pre-order traversal
761 of all the children of the given element.
762 """
763 return IterWalkChildren(elem)
764
765
767 while child:
768 if compare(parent, child):
769 return True
770 child = child.parentNode
771 if not child:
772 return False
773 if child.nodeType != 1:
774 child = None
775 return False
776
777
785
786
788
791
792
794 return elem.offsetHeight
795
796
798 return elem.offsetWidth
799
800
835
836
838 res = ''
839 for c in name:
840 if c.isupper():
841 res += joiner + c.lower()
842 else:
843 res += c
844 return res
845
846
849
850
852
853 setattr(element, attribute, value)
854
855
858
859
861 mf = get_main_frame()
862 setattr(elem, mf.mash_attrib(attr), value)
863
864
870
871
873
875 """
876 Register an object to receive event notifications for the given
877 element. The listener's onBrowserEvent() method will be called
878 when a captured event occurs. To set which events are captured,
879 use sinkEvents().
880 """
881 set_listener(element, listener)
882
883
885 return doc().createTextNode(txt)
886
887
889 try:
890 element.innerHtml = html
891 except:
892 element.innerHTML = html
893
894
895 -def setInnerText(elem, text):
896
897 while elem.firstChild is not None:
898 elem.removeChild(elem.firstChild)
899 elem.appendChild(createTextNode(text or ''))
900
901
904
905
907 setattr(elem, attr, int(value))
908
909
911 mf = get_main_frame()
912 if hasattr(elem.style, 'setProperty'):
913 elem.style.setProperty(mf.mash_attrib(attr), str(value), "")
914 else:
915 elem.style.setAttribute(mf.mash_attrib(attr), str(value), "")
916
917
918 -def setOptionText(select, text, index):
919 option = select.options.item(index)
920 option.textContent = text
921
922
924 if hasattr(element.style, 'setProperty'):
925 element.style.setProperty(mash_name_for_glib(name), value, "")
926 else:
927 element.style.setAttribute(name, value, "")
928
930 """
931 multi attr: setStyleAttributes(self, {attr1:val1, attr2:val2, ...})
932 """
933 for attr, val in kwargs.items():
934 if hasattr(element.style, 'setProperty'):
935 element.style.setProperty(mash_name_for_glib(attr), val, "")
936 else:
937 element.style.setAttribute(attr, val, "")
938
940 """
941 Set which events should be captured on a given element and passed to the
942 registered listener. To set the listener, use setEventListener().
943
944 @param bits: A combination of bits; see ui.Event for bit values
945 """
946 mask = getEventsSunk(element) ^ bits
947 eventbitsmap[element] = bits
948 if not mask:
949 return
950
951 bits = mask
952
953 if not bits:
954 return
955 mf = get_main_frame()
956 if hasattr(mf, "_addEventListener"):
957 aev = mf._addEventListener
958 else:
959 aev = mf.addEventListener
960
961 cb = _dispatchEvent
962
963
964 sinkEventsMozilla(element, bits)
965
966 bit = 1
967 while bits:
968 if bit > bits:
969 raise RuntimeError("sinkEvents: bit outruns bits")
970 if (bits & bit):
971 for event_name in Event.eventbits[bit][1]:
972 aev(element, event_name, cb)
973 bits ^= bit
974 bit <<= 1
975
978
986
987
988
991
992
1008
1009
1010
1013
1014 currentEvent = None
1015
1016
1029
1030
1033
1034
1044
1045
1048
1049
1052
1054 """ these are all different, across all platforms!
1055 """
1056 pass
1057
1058
1059 if not pyjd.is_desktop:
1060 init()
1061