00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import <Foundation/CPObject.j>
00024 @import <Foundation/CPRunLoop.j>
00025
00026 @import "CPEvent.j"
00027 @import "CPCompatibility.j"
00028
00029 @import "CPDOMWindowLayer.j"
00030
00031 #import "../../CoreGraphics/CGGeometry.h"
00032
00033
00034 CPSharedDOMWindowBridge = nil;
00035
00036 var ExcludedDOMElements = [];
00037
00038
00039 var CPDOMWindowGetFrame,
00040 CPDOMEventGetClickCount,
00041 CPDOMEventStop;
00042
00043 @implementation CPDOMWindowBridge : CPObject
00044 {
00045 CPArray _orderedWindows;
00046 CPWindow _mouseDownWindow;
00047
00048 DOMWindow _DOMWindow;
00049 DOMElement _DOMBodyElement;
00050 DOMElement _DOMFocusElement;
00051
00052 CPArray _windowLevels;
00053 CPDictionary _windowLayers;
00054
00055 CPRect _frame;
00056 CPRect _contentBounds;
00057
00058 BOOL _mouseIsDown;
00059 CPTimeInterval _lastMouseUp;
00060 CPTimeInterval _lastMouseDown;
00061
00062 JSObject _charCodes;
00063 unsigned _keyCode;
00064
00065 BOOL _DOMEventMode;
00066
00067
00068 DOMElement _DOMPasteboardElement;
00069 CPEvent _pasteboardKeyDownEvent;
00070
00071 CPString _overriddenEventType;
00072 }
00073
00077 + (id)sharedDOMWindowBridge
00078 {
00079 if (!CPSharedDOMWindowBridge)
00080 CPSharedDOMWindowBridge = [[CPDOMWindowBridge alloc] _initWithDOMWindow:window];
00081
00082 return CPSharedDOMWindowBridge;
00083 }
00084
00085 - (id)initWithFrame:(CPRect)aFrame
00086 {
00087 alert("unimplemented");
00088 }
00089
00090
00091 - (id)_initWithDOMWindow:(DOMWindow)aDOMWindow
00092 {
00093 self = [super init];
00094
00095 if (self)
00096 {
00097 _DOMWindow = aDOMWindow;
00098
00099 _windowLevels = [];
00100 _windowLayers = [CPDictionary dictionary];
00101
00102
00103 _DOMBodyElement = document.getElementsByTagName("body")[0];
00104 _DOMBodyElement.innerHTML = "";
00105 _DOMBodyElement.style.overflow = "hidden";
00106 _DOMBodyElement.style.webkitTouchCallout = "none";
00107
00108 [CPString _resetSize];
00109
00110 if (document.documentElement)
00111 document.documentElement.style.overflow = "hidden";
00112
00113 _frame = CPDOMWindowGetFrame(_DOMWindow);
00114 _contentBounds = CGRectMake(0.0, 0.0, CPRectGetWidth(_frame), CPRectGetHeight(_frame));
00115
00116 _DOMFocusElement = document.createElement("input");
00117 _DOMFocusElement.style.position = "absolute";
00118 _DOMFocusElement.style.zIndex = "-1000";
00119 _DOMFocusElement.style.opacity = "0";
00120 _DOMFocusElement.style.filter = "alpha(opacity=0)";
00121 _DOMBodyElement.appendChild(_DOMFocusElement);
00122
00123
00124 _DOMPasteboardElement = document.createElement("input");
00125 _DOMPasteboardElement.style.position = "absolute";
00126 _DOMPasteboardElement.style.top = "-10000px";
00127 _DOMPasteboardElement.style.zIndex = "99";
00128
00129 _DOMBodyElement.appendChild(_DOMPasteboardElement);
00130
00131
00132 _DOMPasteboardElement.blur();
00133
00134 _charCodes = {};
00135
00136
00137 var theClass = [self class],
00138
00139 keyEventSelector = @selector(_bridgeKeyEvent:),
00140 keyEventImplementation = class_getMethodImplementation(theClass, keyEventSelector),
00141 keyEventCallback = function (anEvent) { keyEventImplementation(self, nil, anEvent); },
00142
00143 mouseEventSelector = @selector(_bridgeMouseEvent:),
00144 mouseEventImplementation = class_getMethodImplementation(theClass, mouseEventSelector),
00145 mouseEventCallback = function (anEvent) { mouseEventImplementation(self, nil, anEvent); },
00146
00147 scrollEventSelector = @selector(_bridgeScrollEvent:),
00148 scrollEventImplementation = class_getMethodImplementation(theClass, scrollEventSelector),
00149 scrollEventCallback = function (anEvent) { scrollEventImplementation(self, nil, anEvent); },
00150
00151 resizeEventSelector = @selector(_bridgeResizeEvent:),
00152 resizeEventImplementation = class_getMethodImplementation(theClass, resizeEventSelector),
00153 resizeEventCallback = function (anEvent) { resizeEventImplementation(self, nil, anEvent); },
00154
00155 touchEventSelector = @selector(_bridgeTouchEvent:),
00156 touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector),
00157 touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); },
00158
00159 theDocument = _DOMWindow.document;
00160
00161 if (document.addEventListener)
00162 {
00163 _DOMWindow.addEventListener("resize", resizeEventCallback, NO);
00164
00165 theDocument.addEventListener(CPDOMEventMouseUp, mouseEventCallback, NO);
00166 theDocument.addEventListener(CPDOMEventMouseDown, mouseEventCallback, NO);
00167 theDocument.addEventListener(CPDOMEventMouseMoved, mouseEventCallback, NO);
00168
00169 theDocument.addEventListener(CPDOMEventKeyUp, keyEventCallback, NO);
00170 theDocument.addEventListener(CPDOMEventKeyDown, keyEventCallback, NO);
00171 theDocument.addEventListener(CPDOMEventKeyPress, keyEventCallback, NO);
00172
00173
00174 theDocument.addEventListener(CPDOMEventTouchStart, touchEventCallback, NO);
00175 theDocument.addEventListener(CPDOMEventTouchEnd, touchEventCallback, NO);
00176 theDocument.addEventListener(CPDOMEventTouchMove, touchEventCallback, NO);
00177 theDocument.addEventListener(CPDOMEventTouchCancel, touchEventCallback, NO);
00178
00179
00180 _DOMWindow.addEventListener("DOMMouseScroll", scrollEventCallback, NO);
00181 _DOMWindow.addEventListener(CPDOMEventScrollWheel, scrollEventCallback, NO);
00182 }
00183 else if(document.attachEvent)
00184 {
00185 _DOMWindow.attachEvent("onresize", resizeEventCallback);
00186
00187 theDocument.attachEvent("on" + CPDOMEventMouseUp, mouseEventCallback);
00188 theDocument.attachEvent("on" + CPDOMEventMouseDown, mouseEventCallback);
00189 theDocument.attachEvent("on" + CPDOMEventMouseMoved, mouseEventCallback);
00190 theDocument.attachEvent("on" + CPDOMEventDoubleClick, mouseEventCallback);
00191
00192 theDocument.attachEvent("on" + CPDOMEventKeyUp, keyEventCallback);
00193 theDocument.attachEvent("on" + CPDOMEventKeyDown, keyEventCallback);
00194 theDocument.attachEvent("on" + CPDOMEventKeyPress, keyEventCallback);
00195
00196 _DOMWindow.onmousewheel = scrollEventCallback;
00197 theDocument.onmousewheel = scrollEventCallback;
00198
00199 theDocument.body.ondrag = function () { return NO; };
00200 theDocument.body.onselectstart = function () { return window.event.srcElement == _DOMPasteboardElement; };
00201 }
00202
00203 ExcludedDOMElements["INPUT"] = YES;
00204 ExcludedDOMElements["SELECT"] = YES;
00205 ExcludedDOMElements["TEXTAREA"] = YES;
00206 ExcludedDOMElements["OPTION"] = YES;
00207 }
00208
00209 return self;
00210 }
00211
00212 - (CPRect)frame
00213 {
00214 return CGRectMakeCopy(_frame);
00215 }
00216
00217 - (CGRect)visibleFrame
00218 {
00219 var frame = [self frame];
00220
00221 frame.origin = CGPointMakeZero();
00222
00223 if ([CPMenu menuBarVisible])
00224 {
00225 var menuBarHeight = [[CPApp mainMenu] menuBarHeight];
00226
00227 frame.origin.y += menuBarHeight;
00228 frame.size.height -= menuBarHeight;
00229 }
00230
00231 return frame;
00232 }
00233
00234 - (CPRect)contentBounds
00235 {
00236 return CPRectCreateCopy(_contentBounds);
00237 }
00238
00239 - (CPArray)orderedWindowsAtLevel:(int)aLevel
00240 {
00241 var layer = [self layerAtLevel:aLevel create:NO];
00242
00243 if (!layer)
00244 return [];
00245
00246 return [layer orderedWindows];
00247 }
00248
00249 - (CPDOMWindowLayer)layerAtLevel:(int)aLevel create:(BOOL)aFlag
00250 {
00251 var layer = [_windowLayers objectForKey:aLevel];
00252
00253
00254
00255 if (!layer && aFlag)
00256 {
00257 layer = [[CPDOMWindowLayer alloc] initWithLevel:aLevel];
00258
00259 [_windowLayers setObject:layer forKey:aLevel];
00260
00261
00262
00263 var low = 0,
00264 high = _windowLevels.length - 1,
00265 middle;
00266
00267 while (low <= high)
00268 {
00269 middle = FLOOR((low + high) / 2);
00270
00271 if (_windowLevels[middle] > aLevel)
00272 high = middle - 1;
00273 else
00274 low = middle + 1;
00275 }
00276
00277 [_windowLevels insertObject:aLevel atIndex:_windowLevels[middle] > aLevel ? middle : middle + 1];
00278 layer._DOMElement.style.zIndex = aLevel;
00279 _DOMBodyElement.appendChild(layer._DOMElement);
00280 }
00281
00282 return layer;
00283 }
00284
00285 - (void)order:(CPWindowOrderingMode)aPlace window:(CPWindow)aWindow relativeTo:(CPWindow)otherWindow
00286 {
00287
00288
00289 var layer = [self layerAtLevel:[aWindow level] create:aPlace != CPWindowOut];
00290
00291
00292
00293 if (aPlace == CPWindowOut)
00294 return [layer removeWindow:aWindow];
00295
00296
00297 [layer insertWindow:aWindow atIndex:(otherWindow ? (aPlace == CPWindowAbove ? otherWindow._index + 1 : otherWindow._index) : CPNotFound)];
00298 }
00299
00300
00301 - (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard
00302 {
00303 var levels = _windowLevels,
00304 layers = _windowLayers,
00305 levelCount = levels.length;
00306
00307 while (levelCount--)
00308 {
00309
00310 if (levels[levelCount] >= CPDraggingWindowLevel)
00311 continue;
00312
00313 var windows = [layers objectForKey:levels[levelCount]]._windows,
00314 windowCount = windows.length;
00315
00316 while (windowCount--)
00317 {
00318 var theWindow = windows[windowCount];
00319
00320 if ([theWindow containsPoint:aPoint])
00321 return [theWindow _dragHitTest:aPoint pasteboard:aPasteboard];
00322 }
00323 }
00324
00325 return nil;
00326 }
00327
00328
00329 - (void)_propagateCurrentDOMEvent:(BOOL)aFlag
00330 {
00331 StopDOMEventPropagation = !aFlag;
00332 }
00333
00334 - (CPWindow)hitTest:(CPPoint)location
00335 {
00336 var levels = _windowLevels,
00337 layers = _windowLayers,
00338 levelCount = levels.length,
00339 theWindow = nil;
00340
00341 while (levelCount-- && !theWindow)
00342 {
00343 var windows = [layers objectForKey:levels[levelCount]]._windows,
00344 windowCount = windows.length;
00345
00346 while (windowCount-- && !theWindow)
00347 {
00348 var candidateWindow = windows[windowCount];
00349
00350 if (!candidateWindow._ignoresMouseEvents && [candidateWindow containsPoint:location])
00351 theWindow = candidateWindow;
00352 }
00353 }
00354
00355 return theWindow;
00356 }
00357
00358 @end
00359
00360 var CPDOMWindowGetFrame = function(_DOMWindow)
00361 {
00362 var frame = nil;
00363
00364
00365 if (_DOMWindow.outerWidth)
00366 frame = CGRectMake(0, 0, _DOMWindow.outerWidth, _DOMWindow.outerHeight);
00367
00368 else
00369 frame = CGRectMake(0, 0, -1, -1);
00370
00371 if (window.screenTop)
00372 frame.origin = CGPointMake(_DOMWindow.screenLeft, _DOMWindow.screenTop, 0);
00373
00374 else if (window.screenX)
00375 frame.origin = CGPointMake(_DOMWindow.screenX, _DOMWindow.screenY, 0);
00376
00377
00378 if (_DOMWindow.innerWidth)
00379 frame.size = CGSizeMake(_DOMWindow.innerWidth, _DOMWindow.innerHeight);
00380
00381
00382 else if (document.documentElement && document.documentElement.clientWidth)
00383 frame.size = CGSizeMake(_DOMWindow.document.documentElement.clientWidth, _DOMWindow.document.documentElement.clientHeight);
00384
00385
00386 else
00387 frame.size = CGSizeMake(_DOMWindow.document.body.clientWidth, _DOMWindow.document.body.clientHeight);
00388
00389 return frame;
00390 }
00391
00392
00393
00394
00395 var KeyCodesToPrevent = {},
00396 CharacterKeysToPrevent = {},
00397 KeyCodesWithoutKeyPressEvents = { '8':1, '9':1, '37':1, '38':1, '39':1, '40':1, '46':1, '33':1, '34':1 };
00398
00399 var CTRL_KEY_CODE = 17;
00400
00401 @implementation CPDOMWindowBridge (Events)
00402
00410 - (void)preventCharacterKeysFromPropagating:(CPArray)characters
00411 {
00412 for(var i=characters.length; i>0; i--)
00413 CharacterKeysToPrevent[""+characters[i-1].toLowerCase()] = YES;
00414 }
00415
00419 - (void)preventCharacterKeyFromPropagating:(CPString)character
00420 {
00421 CharacterKeysToPrevent[character.toLowerCase()] = YES;
00422 }
00423
00427 - (void)clearCharacterKeysToPreventFromPropagating
00428 {
00429 CharacterKeysToPrevent = {};
00430 }
00431
00436 - (void)preventKeyCodesFromPropagating:(CPArray)keyCodes
00437 {
00438 for(var i=keyCodes.length; i>0; i--)
00439 KeyCodesToPrevent[keyCodes[i-1]] = YES;
00440 }
00441
00446 - (void)preventKeyCodeFromPropagating:(CPString)keyCode
00447 {
00448 KeyCodesToPrevent[keyCode] = YES;
00449 }
00450
00454 - (void)clearKeyCodesToPreventFromPropagating
00455 {
00456 KeyCodesToPrevent = {};
00457 }
00458
00459
00460 - (void)_bridgeMouseEvent:(DOMEvent)aDOMEvent
00461 {
00462 var theType = _overriddenEventType || aDOMEvent.type;
00463
00464
00465 if (theType === CPDOMEventDoubleClick)
00466 {
00467 _overriddenEventType = CPDOMEventMouseDown;
00468 [self _bridgeMouseEvent:aDOMEvent];
00469
00470 _overriddenEventType = CPDOMEventMouseUp;
00471 [self _bridgeMouseEvent:aDOMEvent];
00472
00473 _overriddenEventType = nil;
00474
00475 return;
00476 }
00477
00478 try
00479 {
00480 var event,
00481 location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY),
00482 timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
00483 sourceElement = (aDOMEvent.target || aDOMEvent.srcElement),
00484 windowNumber = 0,
00485 modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
00486 (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
00487 (aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
00488 (aDOMEvent.metaKey ? CPCommandKeyMask : 0);
00489
00490 StopDOMEventPropagation = YES;
00491
00492 if (_mouseDownWindow)
00493 windowNumber = [_mouseDownWindow windowNumber];
00494 else
00495 {
00496 var theWindow = [self hitTest:location];
00497
00498 if ((aDOMEvent.type === CPDOMEventMouseDown) && theWindow)
00499 _mouseDownWindow = theWindow;
00500
00501 windowNumber = [theWindow windowNumber];
00502 }
00503
00504 if (windowNumber)
00505 {
00506 var windowFrame = CPApp._windows[windowNumber]._frame;
00507
00508 location.x -= _CGRectGetMinX(windowFrame);
00509 location.y -= _CGRectGetMinY(windowFrame);
00510 }
00511
00512 switch (theType)
00513 {
00514 case CPDOMEventMouseUp: if(_mouseIsDown)
00515 {
00516 event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0);
00517
00518 _mouseIsDown = NO;
00519 _lastMouseUp = event;
00520 _mouseDownWindow = nil;
00521 }
00522
00523 if(_DOMEventMode)
00524 {
00525 _DOMEventMode = NO;
00526 return;
00527 }
00528
00529 break;
00530
00531 case CPDOMEventMouseDown: if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement)
00532 {
00533 _DOMEventMode = YES;
00534 _mouseIsDown = YES;
00535
00536
00537 [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:location modifierFlags:modifierFlags
00538 timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
00539 clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
00540
00541 [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseUp location:location modifierFlags:modifierFlags
00542 timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
00543 clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
00544
00545 return;
00546 }
00547
00548 event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0);
00549
00550 _mouseIsDown = YES;
00551 _lastMouseDown = event;
00552
00553 break;
00554
00555 case CPDOMEventMouseMoved: if (_DOMEventMode)
00556 return;
00557
00558 event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? CPLeftMouseDragged : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0);
00559
00560 break;
00561 }
00562
00563 if (event)
00564 {
00565 event._DOMEvent = aDOMEvent;
00566
00567 [CPApp sendEvent:event];
00568 }
00569
00570 if (StopDOMEventPropagation)
00571 CPDOMEventStop(aDOMEvent);
00572
00573 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00574 }
00575 catch (anException)
00576 {
00577 objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
00578 }
00579 }
00580
00581
00582 - (void)_bridgeKeyEvent:(DOMEvent)aDOMEvent
00583 {
00584 try
00585 {
00586 var event,
00587 timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
00588 sourceElement = (aDOMEvent.target || aDOMEvent.srcElement),
00589 windowNumber = [[CPApp keyWindow] windowNumber],
00590 modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
00591 (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
00592 (aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
00593 (aDOMEvent.metaKey ? CPCommandKeyMask : 0);
00594
00595 if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement && sourceElement != _DOMPasteboardElement)
00596 return;
00597
00598
00599 StopDOMEventPropagation = !(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
00600 CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] ||
00601 KeyCodesToPrevent[aDOMEvent.keyCode];
00602
00603 var isNativePasteEvent = NO,
00604 isNativeCopyOrCutEvent = NO;
00605
00606 switch (aDOMEvent.type)
00607 {
00608 case CPDOMEventKeyDown:
00609 _keyCode = aDOMEvent.keyCode;
00610
00611 var characters = String.fromCharCode(_keyCode).toLowerCase();
00612
00613
00614
00615 if (characters == "v" && (modifierFlags & CPPlatformActionKeyMask))
00616 {
00617 _DOMPasteboardElement.select();
00618 _DOMPasteboardElement.value = "";
00619
00620 isNativePasteEvent = YES;
00621 }
00622
00623
00624
00625
00626
00627
00628 else if ((characters == "c" || characters == "x") && (modifierFlags & CPPlatformActionKeyMask))
00629 isNativeCopyOrCutEvent = YES;
00630
00631
00632
00633 else if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport))
00634 return;
00635
00636
00637 else if (!KeyCodesWithoutKeyPressEvents[_keyCode] && (_keyCode == CTRL_KEY_CODE || !(modifierFlags & CPControlKeyMask)))
00638 return;
00639
00640
00641 case CPDOMEventKeyPress:
00642
00643
00644 if ((aDOMEvent.target || aDOMEvent.srcElement) == _DOMPasteboardElement)
00645 return;
00646
00647 var keyCode = _keyCode,
00648 charCode = aDOMEvent.keyCode || aDOMEvent.charCode,
00649 isARepeat = (_charCodes[keyCode] != nil);
00650
00651 _charCodes[keyCode] = charCode;
00652
00653 var characters = String.fromCharCode(charCode),
00654 charactersIgnoringModifiers = characters.toLowerCase();
00655
00656 event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
00657 timestamp:timestamp windowNumber:windowNumber context:nil
00658 characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:keyCode];
00659
00660 if (isNativePasteEvent)
00661 {
00662 _pasteboardKeyDownEvent = event;
00663
00664 window.setNativeTimeout(function () { [self _checkPasteboardElement] }, 0);
00665
00666 return;
00667 }
00668
00669 break;
00670
00671 case CPDOMEventKeyUp: var keyCode = aDOMEvent.keyCode,
00672 charCode = _charCodes[keyCode];
00673
00674 _charCodes[keyCode] = nil;
00675
00676 var characters = String.fromCharCode(charCode),
00677 charactersIgnoringModifiers = characters.toLowerCase();
00678
00679 if (!(modifierFlags & CPShiftKeyMask))
00680 characters = charactersIgnoringModifiers;
00681
00682 event = [CPEvent keyEventWithType:CPKeyUp location:location modifierFlags:modifierFlags
00683 timestamp: timestamp windowNumber:windowNumber context:nil
00684 characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:keyCode];
00685 break;
00686 }
00687
00688 if (event)
00689 {
00690 event._DOMEvent = aDOMEvent;
00691
00692 [CPApp sendEvent:event];
00693
00694 if (isNativeCopyOrCutEvent)
00695 {
00696 var pasteboard = [CPPasteboard generalPasteboard],
00697 types = [pasteboard types];
00698
00699
00700 if (types.length)
00701 {
00702 if ([types indexOfObjectIdenticalTo:CPStringPboardType] != CPNotFound)
00703 _DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType];
00704 else
00705 _DOMPasteboardElement.value = [pasteboard _generateStateUID];
00706
00707 _DOMPasteboardElement.select();
00708
00709 window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0);
00710 }
00711
00712 return;
00713 }
00714 }
00715
00716 if (StopDOMEventPropagation)
00717 CPDOMEventStop(aDOMEvent);
00718
00719 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00720 }
00721 catch (anException)
00722 {
00723 objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
00724 }
00725 }
00726
00727
00728 - (void)_bridgeScrollEvent:(DOMEvent)aDOMEvent
00729 {
00730 if(!aDOMEvent)
00731 aDOMEvent = window.event;
00732
00733 try
00734 {
00735 if (CPFeatureIsCompatible(CPJavaScriptMouseWheelValues_8_15))
00736 {
00737 var x = 0.0,
00738 y = 0.0,
00739 element = aDOMEvent.target;
00740
00741 while (element.nodeType !== 1)
00742 element = element.parentNode;
00743
00744 if (element.offsetParent)
00745 {
00746 do
00747 {
00748 x += element.offsetLeft;
00749 y += element.offsetTop;
00750
00751 } while (element = element.offsetParent);
00752 }
00753
00754 var location = _CGPointMake((x + ((aDOMEvent.clientX - 8) / 15)), (y + ((aDOMEvent.clientY - 8) / 15)));}
00755 else
00756 var location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY);
00757
00758 var deltaX = 0.0,
00759 deltaY = 0.0,
00760 windowNumber = 0,
00761 timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
00762 modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
00763 (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
00764 (aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
00765 (aDOMEvent.metaKey ? CPCommandKeyMask : 0);
00766
00767 StopDOMEventPropagation = YES;
00768
00769 windowNumber = [[self hitTest:location] windowNumber];
00770
00771 if (!windowNumber)
00772 return;
00773
00774 var windowFrame = CPApp._windows[windowNumber]._frame;
00775
00776 location.x -= CGRectGetMinX(windowFrame);
00777 location.y -= CGRectGetMinY(windowFrame);
00778
00779 if(typeof aDOMEvent.wheelDeltaX != "undefined")
00780 {
00781 deltaX = aDOMEvent.wheelDeltaX / 120.0;
00782 deltaY = aDOMEvent.wheelDeltaY / 120.0;
00783 }
00784
00785 else if (aDOMEvent.wheelDelta)
00786 deltaY = aDOMEvent.wheelDelta / 120.0;
00787
00788 else if (aDOMEvent.detail)
00789 deltaY = -aDOMEvent.detail / 3.0;
00790
00791 else
00792 return;
00793
00794 if(!CPFeatureIsCompatible(CPJavaScriptNegativeMouseWheelValues))
00795 {
00796 deltaX = -deltaX;
00797 deltaY = -deltaY;
00798 }
00799
00800 var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags
00801 timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0 ];
00802
00803 event._DOMEvent = aDOMEvent;
00804 event._deltaX = ROUND(deltaX * 1.5);
00805 event._deltaY = ROUND(deltaY * 1.5);
00806
00807 [CPApp sendEvent:event];
00808
00809 if (StopDOMEventPropagation)
00810 CPDOMEventStop(aDOMEvent);
00811
00812 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00813 }
00814 catch (anException)
00815 {
00816 objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
00817 }
00818
00819 }
00820
00821
00822 - (void)_bridgeResizeEvent:(DOMEvent)aDOMEvent
00823 {
00824 try
00825 {
00826
00827
00828
00829
00830 var oldSize = _frame.size;
00831
00832
00833 _frame = CPDOMWindowGetFrame(_DOMWindow);
00834 _contentBounds.size = CGSizeCreateCopy(_frame.size);
00835
00836 var levels = _windowLevels,
00837 layers = _windowLayers,
00838 levelCount = levels.length;
00839
00840 while (levelCount--)
00841 {
00842 var windows = [layers objectForKey:levels[levelCount]]._windows,
00843 windowCount = windows.length;
00844
00845 while (windowCount--)
00846 [windows[windowCount] resizeWithOldBridgeSize:oldSize];
00847 }
00848
00849
00850
00851 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00852 }
00853 catch (anException)
00854 {
00855 objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
00856 }
00857 }
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869 - (void)_bridgeTouchEvent:(DOMEvent)aDOMEvent
00870 {
00871 try
00872 {
00873 if (aDOMEvent.touches && (aDOMEvent.touches.length == 1 || (aDOMEvent.touches.length == 0 && aDOMEvent.changedTouches.length == 1)))
00874 {
00875 var newEvent = {};
00876
00877 switch(aDOMEvent.type)
00878 {
00879 case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown;
00880 break;
00881 case CPDOMEventTouchEnd: newEvent.type = CPDOMEventMouseUp;
00882 break;
00883 case CPDOMEventTouchMove: newEvent.type = CPDOMEventMouseMoved;
00884 break;
00885 case CPDOMEventTouchCancel: newEvent.type = CPDOMEventMouseUp;
00886 break;
00887 }
00888
00889 var touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0];
00890
00891 newEvent.clientX = touch.clientX;
00892 newEvent.clientY = touch.clientY;
00893
00894 newEvent.timestamp = aDOMEvent.timestamp;
00895 newEvent.target = aDOMEvent.target;
00896
00897 newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false;
00898
00899 newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()};
00900 newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()};
00901
00902 [self _bridgeMouseEvent:newEvent];
00903
00904 return;
00905 }
00906 else
00907 {
00908 if (aDOMEvent.preventDefault)
00909 aDOMEvent.preventDefault();
00910
00911 if (aDOMEvent.stopPropagation)
00912 aDOMEvent.stopPropagation();
00913 }
00914 }
00915 catch(e)
00916 {
00917 objj_exception_report(e, {path:@"CPDOMWindowBridge.j"});
00918 }
00919
00920
00921 }
00922
00923
00924 - (void)_checkPasteboardElement
00925 {
00926 try
00927 {
00928 var value = _DOMPasteboardElement.value;
00929
00930 if ([value length])
00931 {
00932 var pasteboard = [CPPasteboard generalPasteboard];
00933
00934 if ([pasteboard _stateUID] != value)
00935 {
00936 [pasteboard declareTypes:[CPStringPboardType] owner:self];
00937
00938 [pasteboard setString:value forType:CPStringPboardType];
00939 }
00940 }
00941
00942 [self _clearPasteboardElement];
00943
00944 [CPApp sendEvent:_pasteboardKeyDownEvent];
00945
00946 _pasteboardKeyDownEvent = nil;
00947
00948 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00949 }
00950 catch (anException)
00951 {
00952 objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
00953 }
00954 }
00955
00956
00957 - (void)_clearPasteboardElement
00958 {
00959 _DOMPasteboardElement.value = "";
00960 _DOMPasteboardElement.blur();
00961 }
00962
00963 @end
00964
00965 var CLICK_SPACE_DELTA = 5.0,
00966 CLICK_TIME_DELTA = (typeof document != "undefined" && document.addEventListener) ? 350.0 : 1000.0;
00967
00968 var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation)
00969 {
00970 if (!aComparisonEvent)
00971 return 1;
00972
00973 var comparisonLocation = [aComparisonEvent locationInWindow];
00974
00975 return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA &&
00976 ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA &&
00977 ABS(comparisonLocation.y - aLocation.y) < CLICK_SPACE_DELTA) ? [aComparisonEvent clickCount] + 1 : 1;
00978 }
00979
00980 var CPDOMEventStop = function(aDOMEvent)
00981 {
00982
00983 aDOMEvent.cancelBubble = true;
00984 aDOMEvent.returnValue = false;
00985
00986
00987 if (aDOMEvent.preventDefault)
00988 aDOMEvent.preventDefault();
00989
00990 if (aDOMEvent.stopPropagation)
00991 aDOMEvent.stopPropagation();
00992
00993 if (aDOMEvent.type === CPDOMEventMouseDown)
00994 {
00995 CPSharedDOMWindowBridge._DOMFocusElement.focus();
00996 CPSharedDOMWindowBridge._DOMFocusElement.blur();
00997 }
00998 }