mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-26 18:15:36 +00:00
New: added the method performBlock in CPRunLoop
Previously, we could only give a selector and a target for perform in the runLoop. Now we can give a block. This feature is used in the CPTextField class. Previously, when we wanted to call a function at the end of the stack we used window.setTimeout, however due to HTML5 specifications this wasn't called just at the end of the stack but at least 4ms (more information here https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout#Minimum_delay_and_timeout_nesting). Now we give a block to perform, and this block will be performed in the next runloop. Unittest has been added in Tests/Foundation/CPRunLoopTest.j
This commit is contained in:
1 parent
526181a76b
commit
4d1dc0c949
5 files changed
+83
-16
No files matched your search
+3
-2
@@ -843,8 +843,9 @@ var CPComboBoxTextSubview = @"text",
|
||||
// In FireFox this needs to be done in setTimeout, otherwise there is no caret
|
||||
// We have to save the input element now, when we lose focus it will change.
|
||||
var element = [self _inputElement];
|
||||
window.setTimeout(function() {
|
||||
|
||||
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||
{
|
||||
// This will prevent to jump to the focused element
|
||||
var previousScrollingOrigin = [self _scrollToVisibleRectAndReturnPreviousOrigin];
|
||||
|
||||
@@ -852,7 +853,7 @@ var CPComboBoxTextSubview = @"text",
|
||||
|
||||
[self _restorePreviousScrollingOrigin:previousScrollingOrigin];
|
||||
|
||||
}, 0);
|
||||
} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
#endif
|
||||
|
||||
return NO;
|
||||
|
||||
@@ -70,7 +70,6 @@ var CPTextFieldDOMCurrentElement = nil,
|
||||
|
||||
var CPSecureTextFieldCharacter = "\u2022";
|
||||
|
||||
|
||||
function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resigning, didBlurRef)
|
||||
{
|
||||
if (owner && domElement != inputElement.parentNode)
|
||||
@@ -87,7 +86,7 @@ function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resig
|
||||
*/
|
||||
if ([owner _isWithinUsablePlatformRect])
|
||||
{
|
||||
window.setTimeout(function()
|
||||
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||
{
|
||||
// This will prevent to jump to the focused element
|
||||
var previousScrollingOrigin = [owner _scrollToVisibleRectAndReturnPreviousOrigin];
|
||||
@@ -95,7 +94,7 @@ function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resig
|
||||
inputElement.focus();
|
||||
|
||||
[owner _restorePreviousScrollingOrigin:previousScrollingOrigin];
|
||||
}, 0.0);
|
||||
} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,11 +670,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
CPTextFieldInputOwner = self;
|
||||
|
||||
window.setTimeout(function()
|
||||
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||
{
|
||||
/*
|
||||
setTimeout handlers are not guaranteed to fire in the order they were initiated. This can cause a race condition when several windows with text fields are opened quickly, resulting in several instances of this timeout function being fired, perhaps out of order. So we have to check that by the time this function is fired, CPTextFieldInputOwner has not been changed to another text field in the meantime.
|
||||
*/
|
||||
if (CPTextFieldInputOwner !== self)
|
||||
return;
|
||||
|
||||
@@ -693,7 +689,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
_willBecomeFirstResponderByClick = NO;
|
||||
|
||||
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
|
||||
}, 0.0);
|
||||
} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1510,7 +1506,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if (immediately)
|
||||
element.select();
|
||||
else
|
||||
window.setTimeout(function() { element.select(); }, 0);
|
||||
[[CPRunLoop mainRunLoop] performBlock:function(){ element.select(); } argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
}
|
||||
else if (wind !== nil && [wind makeFirstResponder:self])
|
||||
[self _selectText:sender immediately:immediately];
|
||||
|
||||
@@ -448,14 +448,14 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
element.style.width = CGRectGetWidth(contentRect) + "px";
|
||||
element.style.height = [font defaultLineHeightForFont] + "px";
|
||||
|
||||
window.setTimeout(function()
|
||||
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||
{
|
||||
[_tokenScrollView documentView]._DOMElement.appendChild(element);
|
||||
|
||||
//post CPControlTextDidBeginEditingNotification
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
|
||||
window.setTimeout(function()
|
||||
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||
{
|
||||
// This will prevent to jump to the focused element
|
||||
var previousScrollingOrigin = [self _scrollToVisibleRectAndReturnPreviousOrigin];
|
||||
@@ -465,10 +465,10 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
[self _restorePreviousScrollingOrigin:previousScrollingOrigin];
|
||||
|
||||
CPTokenFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
|
||||
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
|
||||
}, 0.0);
|
||||
} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
|
||||
+59
-1
@@ -42,6 +42,7 @@ var _CPRunLoopPerformPool = [],
|
||||
/* @ignore */
|
||||
@implementation _CPRunLoopPerform : CPObject
|
||||
{
|
||||
Function _block;
|
||||
id _target;
|
||||
SEL _selector;
|
||||
id _argument;
|
||||
@@ -64,6 +65,7 @@ var _CPRunLoopPerformPool = [],
|
||||
{
|
||||
var perform = _CPRunLoopPerformPool.pop();
|
||||
|
||||
perform._block = nil;
|
||||
perform._target = aTarget;
|
||||
perform._selector = aSelector;
|
||||
perform._argument = anArgument;
|
||||
@@ -77,6 +79,26 @@ var _CPRunLoopPerformPool = [],
|
||||
return [[self alloc] initWithSelector:aSelector target:aTarget argument:anArgument order:anOrder modes:modes];
|
||||
}
|
||||
|
||||
+ (_CPRunLoopPerform)performWithBlock:(Function)aBlock argument:(id)anArgument order:(unsigned)anOrder modes:(CPArray)modes
|
||||
{
|
||||
if (_CPRunLoopPerformPool.length)
|
||||
{
|
||||
var perform = _CPRunLoopPerformPool.pop();
|
||||
|
||||
perform._target = nil;
|
||||
perform._selector = nil;
|
||||
perform._block = aBlock;
|
||||
perform._argument = anArgument;
|
||||
perform._order = anOrder;
|
||||
perform._runLoopModes = modes;
|
||||
perform._isValid = YES;
|
||||
|
||||
return perform;
|
||||
}
|
||||
|
||||
return [[self alloc] initWithBlock:aBlock argument:anArgument order:anOrder modes:modes];
|
||||
}
|
||||
|
||||
- (id)initWithSelector:(SEL)aSelector target:(SEL)aTarget argument:(id)anArgument order:(unsigned)anOrder modes:(CPArray)modes
|
||||
{
|
||||
self = [super init];
|
||||
@@ -94,6 +116,22 @@ var _CPRunLoopPerformPool = [],
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithBlock:(Function)aBlock argument:(id)anArgument order:(unsigned)anOrder modes:(CPArray)modes
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_block = aBlock;
|
||||
_argument = anArgument;
|
||||
_order = anOrder;
|
||||
_runLoopModes = modes;
|
||||
_isValid = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (SEL)selector
|
||||
{
|
||||
return _selector;
|
||||
@@ -121,7 +159,10 @@ var _CPRunLoopPerformPool = [],
|
||||
|
||||
if ([_runLoopModes containsObject:aRunLoopMode])
|
||||
{
|
||||
[_target performSelector:_selector withObject:_argument];
|
||||
if (_block)
|
||||
_block(_argument);
|
||||
else
|
||||
[_target performSelector:_selector withObject:_argument];
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -225,6 +266,23 @@ var CPRunLoopLastNativeRunLoop = 0;
|
||||
_orderedPerforms.splice(count + 1, 0, perform);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)performBlock:(Function)aBlock argument:(id)anArgument order:(int)anOrder modes:(CPArray)modes
|
||||
{
|
||||
var perform = [_CPRunLoopPerform performWithBlock:aBlock argument:anArgument order:anOrder modes:modes],
|
||||
count = _orderedPerforms.length;
|
||||
|
||||
// We sort ourselves in reverse because we iterate this list backwards.
|
||||
while (count--)
|
||||
if (anOrder < [_orderedPerforms[count] order])
|
||||
break;
|
||||
|
||||
_orderedPerforms.splice(count + 1, 0, perform);
|
||||
}
|
||||
|
||||
/*!
|
||||
Cancels the specified selector and target.
|
||||
@param aSelector the selector of the method to invoke
|
||||
|
||||
@@ -34,6 +34,18 @@
|
||||
[self assert:[10] equals:performer2.callArgs];
|
||||
}
|
||||
|
||||
- (void)testPerformBlock
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||
{i++} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
|
||||
[self assert:i equals:1];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation Performer : CPObject
|
||||
|
||||
Reference in new issue
Block a user