Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FocusManager: don't prevent dragStart event #976

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions eclipse-scout-core/src/focus/FocusManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,38 +413,46 @@ export class FocusManager implements FocusManagerOptions {
* Returns whether to accept a 'mousedown event'.
*/
protected _acceptFocusChangeOnMouseDown($element: JQuery): boolean {
// 1. Prevent focus gain when glasspane is clicked.
// Even if the glasspane is not focusable, this check is required because the glasspane might be contained in a focusable container
// like table. Use case: outline modality with table-page as 'outlineContent'.
// Prevent focus gain when glasspane is clicked.
// Even if the glasspane is not focusable, this check is required because the glasspane might be contained in a focusable container
// like table. Use case: outline modality with table-page as 'outlineContent'.
if ($element.hasClass('glasspane')) {
return false;
}

// 2. Prevent focus gain if covert by glasspane.
// Prevent focus gain if covert by glasspane.
if (this.isElementCovertByGlassPane($element)) {
return false;
}

// 3. Prevent focus gain on elements excluded to gain focus by mouse, e.g. buttons.
// Prevent focus gain on elements excluded to gain focus by mouse, e.g. buttons.
if (!focusUtils.isFocusableByMouse($element)) {
return false;
}

// 4. Allow focus gain on focusable elements.
// Allow focus gain on focusable elements.
if ($element.is(':focusable')) {
return true;
}

// 5. Allow focus gain on elements with selectable content, e.g. the value of a label field.
// Allow focus gain on elements with selectable content, e.g. the value of a label field.
if (focusUtils.isSelectableText($element)) {
return true;
}

// 6. Allow focus gain on elements with a focusable parent, e.g. when clicking on a row in a table.
// Allow focus gain on elements with a focusable parent, e.g. when clicking on a row in a table.
if (focusUtils.containsParentFocusableByMouse($element, $element.entryPoint())) {
return true;
}

// Don't prevent default action for draggable elements which is dragstart event
if (focusUtils.isDraggable($element)) {
// Unfortunately, preventDefault will not only prevent dragstart but also focus gain
// If the draggable element is not focusable, we need to restore the focus later otherwise the desktop would be focused
focusUtils.restoreFocusLater(this.session.$entryPoint);
return true;
}

return false;
}

Expand Down
25 changes: 25 additions & 0 deletions eclipse-scout-core/src/focus/focusUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ export const focusUtils = {
return $element.text().trim().length > 0;
},

/**
* @returns true if the element or one of its parents is draggable.
*/
isDraggable(element: HTMLElement | JQuery): boolean {
let $element = $.ensure(element);
return $element.attr('draggable') === 'true' || $element.parents('[draggable="true"]').length > 0;
},

/**
* Returns true if the given HTML element is the active element in its own document, false otherwise
* @param element
Expand All @@ -94,5 +102,22 @@ export const focusUtils = {
activeElement = ownerDocument.activeElement;
}
return activeElement === element;
},

/**
* Stores the currently focused element and focuses this element again in the next animation frame if the focus changed to the entry point element.
* This is useful if the current task would focus the entry point element which cannot be prevented.
*/
restoreFocusLater($entryPoint: JQuery) {
// queueMicrotask does not work, it looks like the microtask will be executed before the focus change.
// requestAnimationFrame also prevents flickering (compared to setTimeout)
let doc = $entryPoint.document(true);
let prevFocusedElement = doc.activeElement as HTMLElement;
requestAnimationFrame(() => {
let focusedElement = doc.activeElement;
if (focusedElement === $entryPoint[0]) {
prevFocusedElement.focus();
}
});
}
};