Skip to content

Commit

Permalink
feat(cdk-scrollable): add methods to normalize scrolling in RTL (#12607)
Browse files Browse the repository at this point in the history
* feat(cdk-scrollable): add methods to normalize scrolling in RTL

* address comments
  • Loading branch information
mmalerba authored Aug 13, 2018
1 parent 499458c commit 028746a
Show file tree
Hide file tree
Showing 8 changed files with 510 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/

/** Cached result of whether the user's browser supports passive event listeners. */
let supportsPassiveEvents: boolean;

/**
* Checks whether the user's browser supports passive event listeners.
* See: https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
*/
export function supportsPassiveEventListeners(): boolean {
if (supportsPassiveEvents == null && typeof window !== 'undefined') {
try {
window.addEventListener('test', null!, Object.defineProperty({}, 'passive', {
get: () => supportsPassiveEvents = true
}));
} finally {
supportsPassiveEvents = supportsPassiveEvents || false;
}
}

return supportsPassiveEvents;
}

/** Check whether the browser supports scroll behaviors. */
export function supportsScrollBehavior(): boolean {
return !!(document && document.documentElement && document.documentElement.style &&
'scrollBehavior' in document.documentElement.style);
}

/** Cached result Set of input types support by the current browser. */
let supportedInputTypes: Set<string>;

Expand Down
28 changes: 28 additions & 0 deletions src/cdk/platform/features/passive-listeners.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

/** Cached result of whether the user's browser supports passive event listeners. */
let supportsPassiveEvents: boolean;

/**
* Checks whether the user's browser supports passive event listeners.
* See: https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
*/
export function supportsPassiveEventListeners(): boolean {
if (supportsPassiveEvents == null && typeof window !== 'undefined') {
try {
window.addEventListener('test', null!, Object.defineProperty({}, 'passive', {
get: () => supportsPassiveEvents = true
}));
} finally {
supportsPassiveEvents = supportsPassiveEvents || false;
}
}

return supportsPassiveEvents;
}
84 changes: 84 additions & 0 deletions src/cdk/platform/features/scrolling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

/** The possible ways the browser may handle the horizontal scroll axis in RTL languages. */
export enum RtlScrollAxisType {
/**
* scrollLeft is 0 when scrolled all the way left and (scrollWidth - clientWidth) when scrolled
* all the way right.
*/
NORMAL,
/**
* scrollLeft is -(scrollWidth - clientWidth) when scrolled all the way left and 0 when scrolled
* all the way right.
*/
NEGATED,
/**
* scrollLeft is (scrollWidth - clientWidth) when scrolled all the way left and 0 when scrolled
* all the way right.
*/
INVERTED
}

/** Cached result of the way the browser handles the horizontal scroll axis in RTL mode. */
let rtlScrollAxisType: RtlScrollAxisType;

/** Check whether the browser supports scroll behaviors. */
export function supportsScrollBehavior(): boolean {
return !!(typeof document == 'object' && 'scrollBehavior' in document.documentElement.style);
}

/**
* Checks the type of RTL scroll axis used by this browser. As of time of writing, Chrome is NORMAL,
* Firefox & Safari are NEGATED, and IE & Edge are INVERTED.
*/
export function getRtlScrollAxisType(): RtlScrollAxisType {
// We can't check unless we're on the browser. Just assume 'normal' if we're not.
if (typeof document !== 'object' || !document) {
return RtlScrollAxisType.NORMAL;
}

if (!rtlScrollAxisType) {
// Create a 1px wide scrolling container and a 2px wide content element.
const scrollContainer = document.createElement('div');
const containerStyle = scrollContainer.style;
scrollContainer.dir = 'rtl';
containerStyle.height = '1px';
containerStyle.width = '1px';
containerStyle.overflow = 'auto';
containerStyle.visibility = 'hidden';
containerStyle.pointerEvents = 'none';
containerStyle.position = 'absolute';

const content = document.createElement('div');
const contentStyle = content.style;
contentStyle.width = '2px';
contentStyle.height = '1px';

scrollContainer.appendChild(content);
document.body.appendChild(scrollContainer);

rtlScrollAxisType = RtlScrollAxisType.NORMAL;

// The viewport starts scrolled all the way to the right in RTL mode. If we are in a NORMAL
// browser this would mean that the scrollLeft should be 1. If it's zero instead we know we're
// dealing with one of the other two types of browsers.
if (scrollContainer.scrollLeft === 0) {
// In a NEGATED browser the scrollLeft is always somewhere in [-maxScrollAmount, 0]. For an
// INVERTED browser it is always somewhere in [0, maxScrollAmount]. We can determine which by
// setting to the scrollLeft to 1. This is past the max for a NEGATED browser, so it will
// return 0 when we read it again.
scrollContainer.scrollLeft = 1;
rtlScrollAxisType =
scrollContainer.scrollLeft === 0 ? RtlScrollAxisType.NEGATED : RtlScrollAxisType.INVERTED;
}

scrollContainer.parentNode!.removeChild(scrollContainer);
}
return rtlScrollAxisType;
}
4 changes: 3 additions & 1 deletion src/cdk/platform/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@
*/

export * from './platform';
export * from './features';
export * from './platform-module';
export * from './features/input-types';
export * from './features/passive-listeners';
export * from './features/scrolling';
2 changes: 2 additions & 0 deletions src/cdk/scrolling/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ng_module(
module_name = "@angular/cdk/scrolling",
assets = [":virtual-scroll-viewport.css"] + glob(["**/*.html"]),
deps = [
"//src/cdk/bidi",
"//src/cdk/coercion",
"//src/cdk/collections",
"//src/cdk/platform",
Expand All @@ -29,6 +30,7 @@ ts_library(
srcs = glob(["**/*.spec.ts"]),
deps = [
":scrolling",
"//src/cdk/bidi",
"//src/cdk/collections",
"//src/cdk/testing",
"@rxjs",
Expand Down
Loading

0 comments on commit 028746a

Please sign in to comment.