mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-11 18:24:43 +02:00
Refactor to move state changes to browser process
This commit is contained in:
parent
cc277018b7
commit
dbf51382c8
@ -235,6 +235,10 @@ class Application extends BaseApplication {
|
|||||||
return Object.assign({}, this.commandMetadata_);
|
return Object.assign({}, this.commandMetadata_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasGui() {
|
||||||
|
return this.gui() && !this.gui().isDummy();
|
||||||
|
}
|
||||||
|
|
||||||
findCommandByName(name) {
|
findCommandByName(name) {
|
||||||
if (this.commands_[name]) return this.commands_[name];
|
if (this.commands_[name]) return this.commands_[name];
|
||||||
|
|
||||||
|
@ -5,10 +5,9 @@ const path = require('path')
|
|||||||
|
|
||||||
class ElectronAppWrapper {
|
class ElectronAppWrapper {
|
||||||
|
|
||||||
constructor(electronApp, app, store) {
|
constructor(electronApp) {
|
||||||
this.app_ = app;
|
|
||||||
this.electronApp_ = electronApp;
|
this.electronApp_ = electronApp;
|
||||||
this.store_ = store;
|
//this.store_ = store;
|
||||||
this.win_ = null;
|
this.win_ = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,19 +23,23 @@ class ElectronAppWrapper {
|
|||||||
return this.logger_;
|
return this.logger_;
|
||||||
}
|
}
|
||||||
|
|
||||||
store() {
|
window() {
|
||||||
return this.store_;
|
return this.win_;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(action) {
|
// store() {
|
||||||
return this.store().dispatch(action);
|
// return this.store_;
|
||||||
}
|
// }
|
||||||
|
|
||||||
windowContentSize() {
|
// dispatch(action) {
|
||||||
if (!this.win_) return { width: 0, height: 0 };
|
// return this.store().dispatch(action);
|
||||||
const s = this.win_.getContentSize();
|
// }
|
||||||
return { width: s[0], height: s[1] };
|
|
||||||
}
|
// windowContentSize() {
|
||||||
|
// if (!this.win_) return { width: 0, height: 0 };
|
||||||
|
// const s = this.win_.getContentSize();
|
||||||
|
// return { width: s[0], height: s[1] };
|
||||||
|
// }
|
||||||
|
|
||||||
createWindow() {
|
createWindow() {
|
||||||
this.win_ = new BrowserWindow({width: 800, height: 600})
|
this.win_ = new BrowserWindow({width: 800, height: 600})
|
||||||
@ -54,16 +57,16 @@ class ElectronAppWrapper {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.win_.on('resize', () => {
|
this.win_.on('resize', () => {
|
||||||
this.dispatch({
|
// this.dispatch({
|
||||||
type: 'WINDOW_CONTENT_SIZE_SET',
|
// type: 'WINDOW_CONTENT_SIZE_SET',
|
||||||
size: this.windowContentSize(),
|
// size: this.windowContentSize(),
|
||||||
});
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
this.dispatch({
|
// this.dispatch({
|
||||||
type: 'WINDOW_CONTENT_SIZE_SET',
|
// type: 'WINDOW_CONTENT_SIZE_SET',
|
||||||
size: this.windowContentSize(),
|
// size: this.windowContentSize(),
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForElectronAppReady() {
|
async waitForElectronAppReady() {
|
||||||
|
@ -17,14 +17,12 @@ const { ElectronAppWrapper } = require('./ElectronAppWrapper');
|
|||||||
|
|
||||||
class Application extends BaseApplication {
|
class Application extends BaseApplication {
|
||||||
|
|
||||||
constructor(electronApp) {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.electronApp_ = electronApp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gui() {
|
hasGui() {
|
||||||
return this.gui_;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(argv) {
|
async start(argv) {
|
||||||
@ -32,11 +30,11 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
this.initRedux();
|
this.initRedux();
|
||||||
|
|
||||||
this.gui_ = new ElectronAppWrapper(this.electronApp_, this, this.store());
|
//this.gui_ = new ElectronAppWrapper(this.electronApp_, this, this.store());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.gui_.setLogger(this.logger());
|
// this.gui_.setLogger(this.logger());
|
||||||
await this.gui().start();
|
// await this.gui().start();
|
||||||
|
|
||||||
// Since the settings need to be loaded before the store is created, it will never
|
// Since the settings need to be loaded before the store is created, it will never
|
||||||
// receive the SETTINGS_UPDATE_ALL even, which mean state.settings will not be
|
// receive the SETTINGS_UPDATE_ALL even, which mean state.settings will not be
|
||||||
@ -57,7 +55,7 @@ class Application extends BaseApplication {
|
|||||||
id: Setting.value('activeFolderId'),
|
id: Setting.value('activeFolderId'),
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.gui_.exit();
|
//await this.gui_.exit();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +65,8 @@ class Application extends BaseApplication {
|
|||||||
let application_ = null;
|
let application_ = null;
|
||||||
|
|
||||||
function app() {
|
function app() {
|
||||||
if (!application_) throw new Error('Application has not been initialized');
|
//if (!application_) throw new Error('Application has not been initialized');
|
||||||
|
if (!application_) application_ = new Application();
|
||||||
return application_;
|
return application_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
ElectronClient/app/bridge.js
Normal file
36
ElectronClient/app/bridge.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
class Bridge {
|
||||||
|
|
||||||
|
constructor(electronWrapper) {
|
||||||
|
this.electronWrapper_ = electronWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
processArgv() {
|
||||||
|
return process.argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
window() {
|
||||||
|
return this.electronWrapper_.window();
|
||||||
|
}
|
||||||
|
|
||||||
|
windowContentSize() {
|
||||||
|
if (!this.window()) return { width: 0, height: 0 };
|
||||||
|
const s = this.window().getContentSize();
|
||||||
|
return { width: s[0], height: s[1] };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let bridge_ = null;
|
||||||
|
|
||||||
|
function initBridge(wrapper) {
|
||||||
|
if (bridge_) throw new Error('Bridge already initialized');
|
||||||
|
bridge_ = new Bridge(wrapper);
|
||||||
|
return bridge_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bridge() {
|
||||||
|
if (!bridge_) throw new Error('Bridge not initialized');
|
||||||
|
return bridge_;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { bridge, initBridge }
|
@ -1,3 +1,5 @@
|
|||||||
|
const React = require('react');
|
||||||
|
|
||||||
class ItemList extends React.Component {
|
class ItemList extends React.Component {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -6,34 +8,32 @@ class ItemList extends React.Component {
|
|||||||
this.scrollTop_ = 0;
|
this.scrollTop_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
updateStateItemIndexes(props) {
|
||||||
|
if (typeof props === 'undefined') props = this.props;
|
||||||
|
|
||||||
|
const topItemIndex = Math.floor(this.scrollTop_ / props.itemHeight);
|
||||||
|
const visibleItemCount = Math.ceil(props.style.height / props.itemHeight);
|
||||||
|
|
||||||
|
let bottomItemIndex = topItemIndex + visibleItemCount;
|
||||||
|
if (bottomItemIndex >= props.items.length) bottomItemIndex = props.items.length - 1;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
topItemIndex: this.topItemIndex(),
|
topItemIndex: topItemIndex,
|
||||||
bottomItemIndex: this.bottomItemIndex(),
|
bottomItemIndex: bottomItemIndex,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this.updateStateItemIndexes();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(newProps) {
|
||||||
|
this.updateStateItemIndexes(newProps);
|
||||||
|
}
|
||||||
|
|
||||||
onScroll(scrollTop) {
|
onScroll(scrollTop) {
|
||||||
this.scrollTop_ = scrollTop;
|
this.scrollTop_ = scrollTop;
|
||||||
|
this.updateStateItemIndexes();
|
||||||
this.setState({
|
|
||||||
topItemIndex: this.topItemIndex(),
|
|
||||||
bottomItemIndex: this.bottomItemIndex(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
topItemIndex() {
|
|
||||||
return Math.floor(this.scrollTop_ / this.props.itemHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
visibleItemCount() {
|
|
||||||
return Math.ceil(this.props.style.height / this.props.itemHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
bottomItemIndex() {
|
|
||||||
let r = this.topItemIndex() + this.visibleItemCount();
|
|
||||||
if (r >= this.props.items.length) r = this.props.items.length - 1;
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
const { ItemList } = require('./ItemList.min.js');
|
const { ItemList } = require('./ItemList.min.js');
|
||||||
|
const React = require('react');
|
||||||
|
const { connect } = require('react-redux');
|
||||||
|
|
||||||
class NoteListComponent extends React.Component {
|
class NoteListComponent extends React.Component {
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
//const { BaseModel } = require('lib/base-model.js');
|
//const { BaseModel } = require('lib/base-model.js');
|
||||||
|
|
||||||
|
const React = require('react');
|
||||||
|
const { connect } = require('react-redux');
|
||||||
|
|
||||||
class NoteTextComponent extends React.Component {
|
class NoteTextComponent extends React.Component {
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
@ -3,13 +3,47 @@ const { render } = require('react-dom');
|
|||||||
const { createStore } = require('redux');
|
const { createStore } = require('redux');
|
||||||
const { connect, Provider } = require('react-redux');
|
const { connect, Provider } = require('react-redux');
|
||||||
|
|
||||||
const { NoteList } = require('./gui/NoteList.min.js');
|
const { NoteList } = require('./NoteList.min.js');
|
||||||
const { NoteText } = require('./gui/NoteText.min.js');
|
const { NoteText } = require('./NoteText.min.js');
|
||||||
|
|
||||||
const { app } = require('electron').remote.require('./app');
|
const { app } = require('../app');
|
||||||
|
|
||||||
|
const { bridge } = require('electron').remote.require('./bridge');
|
||||||
|
|
||||||
|
//const { app } = require('electron').remote.require('./app');
|
||||||
|
|
||||||
|
async function initialize(dispatch) {
|
||||||
|
bridge().window().on('resize', function() {
|
||||||
|
store.dispatch({
|
||||||
|
type: 'WINDOW_CONTENT_SIZE_SET',
|
||||||
|
size: bridge().windowContentSize(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
store.dispatch({
|
||||||
|
type: 'WINDOW_CONTENT_SIZE_SET',
|
||||||
|
size: bridge().windowContentSize(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
class ReactRootComponent extends React.Component {
|
class ReactRootComponent extends React.Component {
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
if (this.props.appState == 'starting') {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'SET_APP_STATE',
|
||||||
|
state: 'initializing',
|
||||||
|
});
|
||||||
|
|
||||||
|
await initialize(this.props.dispatch);
|
||||||
|
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'SET_APP_STATE',
|
||||||
|
state: 'ready',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const style = {
|
const style = {
|
||||||
width: this.props.size.width,
|
width: this.props.size.width,
|
||||||
@ -33,7 +67,7 @@ class ReactRootComponent extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div style={style}>
|
<div style={style}>
|
||||||
<NoteList itemHeight={40} style={noteListStyle}></NoteList>
|
<NoteList itemHeight={40} style={noteListStyle}></NoteList>
|
||||||
<NoteText style={noteTextStyle}></NoteText>
|
{/*<NoteText style={noteTextStyle}></NoteText>*/}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -43,6 +77,7 @@ class ReactRootComponent extends React.Component {
|
|||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
return {
|
return {
|
||||||
size: state.windowContentSize,
|
size: state.windowContentSize,
|
||||||
|
appState: state.appState,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="react-root"></div>
|
<div id="react-root"></div>
|
||||||
<script src="gui/Root.min.js"></script>
|
<!-- <script src="gui/Root.min.js"></script> -->
|
||||||
|
<script src="main-html.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
40
ElectronClient/app/main-html.js
Normal file
40
ElectronClient/app/main-html.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Make it possible to require("/lib/...") without specifying full path
|
||||||
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
|
const { app } = require('./app.js');
|
||||||
|
const { Folder } = require('lib/models/folder.js');
|
||||||
|
const { Resource } = require('lib/models/resource.js');
|
||||||
|
const { BaseItem } = require('lib/models/base-item.js');
|
||||||
|
const { Note } = require('lib/models/note.js');
|
||||||
|
const { Tag } = require('lib/models/tag.js');
|
||||||
|
const { NoteTag } = require('lib/models/note-tag.js');
|
||||||
|
const { Setting } = require('lib/models/setting.js');
|
||||||
|
const { Logger } = require('lib/logger.js');
|
||||||
|
const { FsDriverNode } = require('lib/fs-driver-node.js');
|
||||||
|
const { shimInit } = require('lib/shim-init-node.js');
|
||||||
|
|
||||||
|
const { bridge } = require('electron').remote.require('./bridge');
|
||||||
|
|
||||||
|
const fsDriver = new FsDriverNode();
|
||||||
|
Logger.fsDriver_ = fsDriver;
|
||||||
|
Resource.fsDriver_ = fsDriver;
|
||||||
|
|
||||||
|
// That's not good, but it's to avoid circular dependency issues
|
||||||
|
// in the BaseItem class.
|
||||||
|
BaseItem.loadClass('Note', Note);
|
||||||
|
BaseItem.loadClass('Folder', Folder);
|
||||||
|
BaseItem.loadClass('Resource', Resource);
|
||||||
|
BaseItem.loadClass('Tag', Tag);
|
||||||
|
BaseItem.loadClass('NoteTag', NoteTag);
|
||||||
|
|
||||||
|
Setting.setConstant('appId', 'net.cozic.joplin-desktop');
|
||||||
|
Setting.setConstant('appType', 'desktop');
|
||||||
|
|
||||||
|
shimInit();
|
||||||
|
|
||||||
|
app().start(bridge().processArgv()).then(() => {
|
||||||
|
require('./gui/Root.min.js');
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('Fatal error:');
|
||||||
|
console.error(error);
|
||||||
|
});
|
@ -2,43 +2,61 @@
|
|||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const electronApp = require('electron').app;
|
const electronApp = require('electron').app;
|
||||||
const { initApp } = require('./app.js');
|
const { ElectronAppWrapper } = require('./ElectronAppWrapper');
|
||||||
const { Folder } = require('lib/models/folder.js');
|
const { initBridge } = require('./bridge');
|
||||||
const { Resource } = require('lib/models/resource.js');
|
|
||||||
const { BaseItem } = require('lib/models/base-item.js');
|
|
||||||
const { Note } = require('lib/models/note.js');
|
|
||||||
const { Tag } = require('lib/models/tag.js');
|
|
||||||
const { NoteTag } = require('lib/models/note-tag.js');
|
|
||||||
const { Setting } = require('lib/models/setting.js');
|
|
||||||
const { Logger } = require('lib/logger.js');
|
|
||||||
const { FsDriverNode } = require('lib/fs-driver-node.js');
|
|
||||||
const { shimInit } = require('lib/shim-init-node.js');
|
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason, p) => {
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
const fsDriver = new FsDriverNode();
|
const wrapper = new ElectronAppWrapper(electronApp);
|
||||||
Logger.fsDriver_ = fsDriver;
|
|
||||||
Resource.fsDriver_ = fsDriver;
|
|
||||||
|
|
||||||
// That's not good, but it's to avoid circular dependency issues
|
initBridge(wrapper);
|
||||||
// in the BaseItem class.
|
|
||||||
BaseItem.loadClass('Note', Note);
|
|
||||||
BaseItem.loadClass('Folder', Folder);
|
|
||||||
BaseItem.loadClass('Resource', Resource);
|
|
||||||
BaseItem.loadClass('Tag', Tag);
|
|
||||||
BaseItem.loadClass('NoteTag', NoteTag);
|
|
||||||
|
|
||||||
Setting.setConstant('appId', 'net.cozic.joplin-desktop');
|
wrapper.start().catch((error) => {
|
||||||
Setting.setConstant('appType', 'desktop');
|
console.error('Electron App fatal error:');
|
||||||
|
|
||||||
shimInit();
|
|
||||||
|
|
||||||
const app = initApp(electronApp);
|
|
||||||
|
|
||||||
app.start(process.argv).catch((error) => {
|
|
||||||
console.error('Fatal error:');
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// const electronApp = require('electron').app;
|
||||||
|
// const { initApp } = require('./app.js');
|
||||||
|
// const { Folder } = require('lib/models/folder.js');
|
||||||
|
// const { Resource } = require('lib/models/resource.js');
|
||||||
|
// const { BaseItem } = require('lib/models/base-item.js');
|
||||||
|
// const { Note } = require('lib/models/note.js');
|
||||||
|
// const { Tag } = require('lib/models/tag.js');
|
||||||
|
// const { NoteTag } = require('lib/models/note-tag.js');
|
||||||
|
// const { Setting } = require('lib/models/setting.js');
|
||||||
|
// const { Logger } = require('lib/logger.js');
|
||||||
|
// const { FsDriverNode } = require('lib/fs-driver-node.js');
|
||||||
|
// const { shimInit } = require('lib/shim-init-node.js');
|
||||||
|
|
||||||
|
// process.on('unhandledRejection', (reason, p) => {
|
||||||
|
// console.error('Unhandled promise rejection', p, 'reason:', reason);
|
||||||
|
// process.exit(1);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const fsDriver = new FsDriverNode();
|
||||||
|
// Logger.fsDriver_ = fsDriver;
|
||||||
|
// Resource.fsDriver_ = fsDriver;
|
||||||
|
|
||||||
|
// // That's not good, but it's to avoid circular dependency issues
|
||||||
|
// // in the BaseItem class.
|
||||||
|
// BaseItem.loadClass('Note', Note);
|
||||||
|
// BaseItem.loadClass('Folder', Folder);
|
||||||
|
// BaseItem.loadClass('Resource', Resource);
|
||||||
|
// BaseItem.loadClass('Tag', Tag);
|
||||||
|
// BaseItem.loadClass('NoteTag', NoteTag);
|
||||||
|
|
||||||
|
// Setting.setConstant('appId', 'net.cozic.joplin-desktop');
|
||||||
|
// Setting.setConstant('appType', 'desktop');
|
||||||
|
|
||||||
|
// shimInit();
|
||||||
|
|
||||||
|
// const app = initApp(electronApp);
|
||||||
|
|
||||||
|
// app.start(process.argv).catch((error) => {
|
||||||
|
// console.error('Fatal error:');
|
||||||
|
// console.error(error);
|
||||||
|
// });
|
@ -192,6 +192,10 @@ class BaseApplication {
|
|||||||
return o.join(', ');
|
return o.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasGui() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
generalMiddleware() {
|
generalMiddleware() {
|
||||||
const middleware = store => next => async (action) => {
|
const middleware = store => next => async (action) => {
|
||||||
this.logger().debug('Reducer action', this.reducerActionToString(action));
|
this.logger().debug('Reducer action', this.reducerActionToString(action));
|
||||||
@ -213,7 +217,7 @@ class BaseApplication {
|
|||||||
await this.refreshNotes(BaseModel.TYPE_SEARCH, action.id);
|
await this.refreshNotes(BaseModel.TYPE_SEARCH, action.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.gui() && action.type == 'SETTINGS_UPDATE_ONE' && action.key == 'sync.interval' || action.type == 'SETTINGS_UPDATE_ALL') {
|
if (this.hasGui() && action.type == 'SETTINGS_UPDATE_ONE' && action.key == 'sync.interval' || action.type == 'SETTINGS_UPDATE_ALL') {
|
||||||
reg.setupRecurrentSync();
|
reg.setupRecurrentSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,8 +15,12 @@ shim.fs = null;
|
|||||||
shim.FileApiDriverLocal = null;
|
shim.FileApiDriverLocal = null;
|
||||||
shim.readLocalFileBase64 = () => { throw new Error('Not implemented'); }
|
shim.readLocalFileBase64 = () => { throw new Error('Not implemented'); }
|
||||||
shim.uploadBlob = () => { throw new Error('Not implemented'); }
|
shim.uploadBlob = () => { throw new Error('Not implemented'); }
|
||||||
shim.setInterval = setInterval;
|
shim.setInterval = function(fn, interval) {
|
||||||
shim.clearInterval = clearInterval;
|
return setInterval(fn, interval);
|
||||||
|
}
|
||||||
|
shim.clearInterval = function(id) {
|
||||||
|
return clearInterval(id);
|
||||||
|
}
|
||||||
shim.detectAndSetLocale = null;
|
shim.detectAndSetLocale = null;
|
||||||
|
|
||||||
module.exports = { shim };
|
module.exports = { shim };
|
Loading…
Reference in New Issue
Block a user