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

feat: prevent timing out one tab or window if another tab have activity #33

Merged
merged 4 commits into from
Feb 9, 2017
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ typings
# Build artifacts
dist
.tmp

# VS Code config
.vscode
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ An interrupt is any source of input (typically from the user, but could be thing
### Extensible Expiry
Another feature ported from `ng-idle` is the ability to store an expiry value in some store where multiple tabs or windows running the same application can write to. Commonly, this store is the `localStorage`, but could be cookies or whatever you want. The purpose of this expiry and the expiry store is twofold: First, to prevent a window from not timing out if it sleeps or pauses longer than the configured timeout period. Second, it can be used so that activity in one tab or window prevents other tabs or windows in the same application from timing out.

By default, a `SimpleExpiry` type is provided, which will just keep track of the expiry in memory. It will fulfill the first purpose mentioned above, but it will not fulfill the second. In other words, `SimpleExpiry` does not coordinate last activity between tabs or windows; you'll need to use or create an implementation that supports that. An official implementation of that using `localStorage` is forthcoming. You can create your own by extending `IdleExpiry` or `SimpleExpiry` and configuring it as a provider for the `IdleExpiry` class.

**NOTE** An `IdleExpiry` implementation must be configured. If you don't care about or need this functionality, just use the default `SimpleExpiry` (this is included in `IDLE_PROVIDERS`).
By default, a `LocalStorageExpiry` type is provided, which will just keep track of the expiry in the localStorage. It will fulfill all purposes mentioned above. If you don't want to support multiple tabs or windows, you can use `SimpleExpiry`. In other words, `SimpleExpiry` does not coordinate last activity between tabs or windows. If you want to store the expiry value in another store, like cookies, you'll need to use or create an implementation that supports that. You can create your own by extending `IdleExpiry` or `SimpleExpiry` and configuring it as a provider for the `IdleExpiry` class.

### Multiple Idle Instance Support
The dependency injector in Angular 2 supports a hierarchical injection strategy. This allows you to create an instance of `Idle` at whatever scope you need, and there can be more than one instance. This allows you two have two separate watches, for example, on two different elements on the page.
Expand Down
6 changes: 5 additions & 1 deletion modules/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import {DocumentInterruptSource} from './src/documentinterruptsource';
import {StorageInterruptSource} from './src/storageinterruptsource';

export * from './src/idle';
export * from './src/interruptargs';
export * from './src/interruptsource';
export * from './src/eventtargetinterruptsource';
export * from './src/documentinterruptsource';
export * from './src/windowinterruptsource';
export * from './src/storageinterruptsource';
export * from './src/keepalivesvc';
export * from './src/idleexpiry';
export * from './src/simpleexpiry';
export * from './src/localstorage';
export * from './src/localstorageexpiry';

export const DEFAULT_INTERRUPTSOURCES: any[] = [new DocumentInterruptSource(
'mousemove keydown DOMMouseScroll mousewheel mousedown touchstart touchmove scroll')];
'mousemove keydown DOMMouseScroll mousewheel mousedown touchstart touchmove scroll'), new StorageInterruptSource()];

export {NgIdleModule} from './src/module';
42 changes: 42 additions & 0 deletions modules/core/src/alternativestorage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { AlternativeStorage } from './alternativestorage';

describe('core/AlternativeStorage', () => {

let storage: Storage;

beforeEach(() => {
storage = new AlternativeStorage();
});

it('setItem() and getItem() should works properly', () => {
expect(storage.getItem('key')).toBeNull();
storage.setItem('key', 'value');
expect(storage.getItem('key')).toBe('value');
});

it('length() returns current value', () => {
expect(storage.length).toBe(0);
storage.setItem('key', 'value');
expect(storage.length).toBe(1);
});

it('clear() must clear current storage', () => {
storage.setItem('key', 'value');
expect(storage.length).toBe(1);
storage.clear();
expect(storage.length).toBe(0);
});

it('key() must return key name ', () => {
expect(storage.key(0)).toBeNull();
storage.setItem('key', 'value');
expect(storage.key(0)).toBe('key');
});

it('remove() must remove item', () => {
storage.setItem('key', 'value');
storage.removeItem('key');
expect(storage.getItem('key')).toBeNull();
});

});
67 changes: 67 additions & 0 deletions modules/core/src/alternativestorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Represents an alternative storage for browser that doesn't support localstorage. (i.e. Safari in private mode)
* @implements Storage
*/
export class AlternativeStorage implements Storage {
private storageMap: any = {};

/*
* Returns an integer representing the number of data items stored in the storageMap object.
*/
get length() {
return Object.keys(this.storageMap).length;
};

/*
* Remove all keys out of the storage.
*/
clear(): void {
this.storageMap = {};
}

/*
* Return the key's value
*
* @param key - name of the key to retrieve the value of.
* @return The key's value
*/
getItem(key: string): string | null {
if (typeof this.storageMap[key] !== 'undefined' ) {
return this.storageMap[key];
}
return null;
}

/*
* Return the nth key in the storage
*
* @param index - the number of the key you want to get the name of.
* @return The name of the key.
*/
key(index: number): string | null {
return Object.keys(this.storageMap)[index] || null;
}

/*
* Remove a key from the storage.
*
* @param key - the name of the key you want to remove.
*/
removeItem(key: string): void {
this.storageMap[key] = undefined;
};

/*
* Add a key to the storage, or update a key's value if it already exists.
*
* @param key - the name of the key.
* @param value - the value you want to give to the key.
*/
setItem(key: string, value: string): void {
this.storageMap[key] = value;
};

[key: string]: any;
[index: number]: string;

}
Loading