diff --git a/doc/readme.md b/doc/readme.md
index 4507ac14..cf53639f 100644
--- a/doc/readme.md
+++ b/doc/readme.md
@@ -17,6 +17,7 @@ You will find here a complete reference of every feature, class or object
provided by Owl.
- [Animations](reference/animations.md)
+- [Browser](reference/browser.md)
- [Component](reference/component.md)
- [Content](reference/content.md)
- [Concurrency Model](reference/concurrency_model.md)
diff --git a/doc/reference/animations.md b/doc/reference/animations.md
index ba23a586..3a4ff190 100644
--- a/doc/reference/animations.md
+++ b/doc/reference/animations.md
@@ -52,7 +52,7 @@ sequence of events will happen:
At node insertion:
- the css classes `name-enter` and `name-enter-active` will be added directly
- when the node is inserted into the DOM.
+ when the node is inserted into the DOM.
- on the next animation frame: the css class `name-enter` will be removed and the
class `name-enter-to` will be added (so they can be used to trigger css
transition effects).
@@ -115,11 +115,13 @@ If you use SCSS, you can use mixins to make generic animations. Here is an exemp
```
Usage:
+
```scss
@include animation-fade(0.5s, "o_notification");
```
-You can now have in your template:
+You can now have in your template:
+
```xml
```
diff --git a/doc/reference/browser.md b/doc/reference/browser.md
new file mode 100644
index 00000000..fd7b3724
--- /dev/null
+++ b/doc/reference/browser.md
@@ -0,0 +1,33 @@
+# 🦉 Browser 🦉
+
+## Content
+
+- [Overview](#overview)
+- [Browser Content](#browser-content)
+
+## Overview
+
+The browser object contains some browser native APIs, such as `setTimeout`, that
+are used by Owl and its utility functions. They are exposed with the intent of
+making them mockable if necessary.
+
+```js
+owl.browser.setTimeout === window.setTimeout; // return true
+```
+
+For now, this object contains some functions that are not used by Owl. They
+will eventually be removed in Owl 2.0.
+
+## Browser Content
+
+More specifically, the `browser` object contains the following methods and objects:
+
+- `setTimeout`
+- `clearTimeout`
+- `setInterval`
+- `clearInterval`
+- `requestAnimationFrame`
+- `random`
+- `Date`
+- `fetch`
+- `localStorage`
diff --git a/doc/reference/content.md b/doc/reference/content.md
index 54d74508..8f272579 100644
--- a/doc/reference/content.md
+++ b/doc/reference/content.md
@@ -7,6 +7,7 @@ For example, `Component` is available at `owl.Component` and `EventBus` is
exported as `owl.core.EventBus`.
```
+browser
Component misc
Context AsyncRoot
QWeb Portal
diff --git a/doc/reference/environment.md b/doc/reference/environment.md
index 21f62b7d..d3f22307 100644
--- a/doc/reference/environment.md
+++ b/doc/reference/environment.md
@@ -133,17 +133,4 @@ the `QWeb` instance and a `browser` object:
- `qweb` will be set to an empty `QWeb` instance. This is absolutely necessary
for Owl to be able to render anything
- `browser`: this is an object that contains some common access points to the
- browser methods with a side effect. This is particularly useful when one want
- to test more advanced components, and be able to mock those methods.
-
-More specifically, the `browser` object contains the following methods and objects:
-
-- `setTimeout`
-- `clearTimeout`
-- `setInterval`
-- `clearInterval`
-- `requestAnimationFrame`
-- `random`
-- `Date`
-- `fetch`
-- `localStorage`
+ browser methods with a side effect. See [browser](browser.md) for more information. Note that the browser object will be removed from the environment in Owl 2.0.
diff --git a/src/browser.ts b/src/browser.ts
index f47a6620..b18d44dd 100644
--- a/src/browser.ts
+++ b/src/browser.ts
@@ -10,6 +10,8 @@ export interface Browser {
localStorage: Window["localStorage"];
}
+let localStorage: Window["localStorage"] | null = null;
+
export const browser: Browser = {
setTimeout: window.setTimeout.bind(window),
clearTimeout: window.clearTimeout.bind(window),
@@ -19,5 +21,10 @@ export const browser: Browser = {
random: Math.random,
Date: window.Date,
fetch: (window.fetch || (() => {})).bind(window),
- localStorage: window.localStorage,
+ get localStorage() {
+ return localStorage || window.localStorage;
+ },
+ set localStorage(newLocalStorage: Window["localStorage"]) {
+ localStorage = newLocalStorage;
+ },
};
diff --git a/src/component/component.ts b/src/component/component.ts
index faafa16f..ded8cca4 100644
--- a/src/component/component.ts
+++ b/src/component/component.ts
@@ -159,6 +159,7 @@ export class Component {
if (!this.env.qweb) {
this.env.qweb = new QWeb();
}
+ // TODO: remove this in owl 2.0
if (!this.env.browser) {
this.env.browser = browser;
}
diff --git a/src/index.ts b/src/index.ts
index f4d6ff1a..e2fada72 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -22,6 +22,7 @@ import { Router } from "./router/router";
export { Component, mount } from "./component/component";
export { QWeb };
export { config };
+export { browser } from "./browser";
export const Context = _context.Context;
export const useState = _hooks.useState;