Feature(mousetrap): Add mousetrap features to redux
This commit is contained in:
@ -45,7 +45,8 @@ const sagaOptions = {
|
|||||||
isDev,
|
isDev,
|
||||||
window,
|
window,
|
||||||
document: window.document,
|
document: window.document,
|
||||||
location: window.location
|
location: window.location,
|
||||||
|
history: window.history
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,16 +1,10 @@
|
|||||||
import { hardGoTo } from '../../common/app/redux/types';
|
import { hardGoTo } from '../../common/app/redux/types';
|
||||||
|
|
||||||
export default function hardGoToSaga(action$, getState, { location }) {
|
export default function hardGoToSaga(action$, getState, { history }) {
|
||||||
return action$
|
return action$
|
||||||
.filter(({ type }) => type === hardGoTo)
|
.filter(({ type }) => type === hardGoTo)
|
||||||
.map(({ payload = '/map' }) => {
|
.map(({ payload = '/settings' }) => {
|
||||||
if (!location.pathname) {
|
history.push(history.state, null, payload);
|
||||||
return {
|
|
||||||
type: 'app.error',
|
|
||||||
error: new Error('no location object found')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
location.pathname = payload;
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import executeChallengeSaga from './execute-challenge-saga';
|
|||||||
import frameSaga from './frame-saga';
|
import frameSaga from './frame-saga';
|
||||||
import codeStorageSaga from './code-storage-saga';
|
import codeStorageSaga from './code-storage-saga';
|
||||||
import gitterSaga from './gitter-saga';
|
import gitterSaga from './gitter-saga';
|
||||||
|
import mouseTrapSaga from './mouse-trap-saga';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
errSaga,
|
errSaga,
|
||||||
@ -15,5 +16,6 @@ export default [
|
|||||||
executeChallengeSaga,
|
executeChallengeSaga,
|
||||||
frameSaga,
|
frameSaga,
|
||||||
codeStorageSaga,
|
codeStorageSaga,
|
||||||
gitterSaga
|
gitterSaga,
|
||||||
|
mouseTrapSaga
|
||||||
];
|
];
|
||||||
|
41
client/sagas/mouse-trap-saga.js
Normal file
41
client/sagas/mouse-trap-saga.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { Observable } from 'rx';
|
||||||
|
import MouseTrap from 'mousetrap';
|
||||||
|
import { push } from 'react-router-redux';
|
||||||
|
import {
|
||||||
|
toggleNightMode,
|
||||||
|
toggleMapDrawer,
|
||||||
|
toggleMainChat,
|
||||||
|
hardGoTo
|
||||||
|
} from '../../common/app/redux/actions';
|
||||||
|
|
||||||
|
function bindKey$(key, actionCreator) {
|
||||||
|
return Observable.fromEventPattern(
|
||||||
|
h => MouseTrap.bind(key, h),
|
||||||
|
h => MouseTrap.unbind(key, h)
|
||||||
|
)
|
||||||
|
.map(actionCreator);
|
||||||
|
}
|
||||||
|
|
||||||
|
const softRedirects = {
|
||||||
|
'g n n': '/challenges/next-challenge',
|
||||||
|
'g n a': '/about',
|
||||||
|
'g n m': '/map',
|
||||||
|
'g n w': '/wiki',
|
||||||
|
'g n s': '/shop',
|
||||||
|
'g n o': '/settings'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function mouseTrapSaga(actions$) {
|
||||||
|
const traps$ = [
|
||||||
|
...Object.keys(softRedirects)
|
||||||
|
.map(key => bindKey$(key, () => push(softRedirects[key]))),
|
||||||
|
bindKey$(
|
||||||
|
'g n r',
|
||||||
|
() => hardGoTo('https://github.com/freecodecamp/freecodecamp')
|
||||||
|
),
|
||||||
|
bindKey$('g m', toggleMapDrawer),
|
||||||
|
bindKey$('g t n', toggleNightMode),
|
||||||
|
bindKey$('g c', toggleMainChat)
|
||||||
|
];
|
||||||
|
return Observable.merge(traps$).takeUntil(actions$.last());
|
||||||
|
}
|
@ -1,26 +1,22 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { hardGoTo } from '../../redux/actions';
|
||||||
|
|
||||||
const win = typeof window !== 'undefined' ? window : {};
|
export class NotFound extends React.Component {
|
||||||
|
|
||||||
function goToServer(path) {
|
|
||||||
win.location = '/' + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class extends React.Component {
|
|
||||||
static displayName = 'NotFound';
|
static displayName = 'NotFound';
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
params: PropTypes.object
|
location: PropTypes.object,
|
||||||
|
hardGoTo: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
goToServer(this.props.params.splat);
|
this.props.hardGoTo(this.props.location.pathname);
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <span></span>;
|
return <span></span>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default connect(null, { hardGoTo })(NotFound);
|
||||||
|
@ -56,3 +56,4 @@ export const toggleWikiDrawer = createAction(types.toggleWikiDrawer);
|
|||||||
|
|
||||||
// chat
|
// chat
|
||||||
export const toggleMainChat = createAction(types.toggleMainChat);
|
export const toggleMainChat = createAction(types.toggleMainChat);
|
||||||
|
export const toggleNightMode = createAction(types.toggleNightMode);
|
||||||
|
@ -9,6 +9,7 @@ export default createTypes([
|
|||||||
'makeToast',
|
'makeToast',
|
||||||
'updatePoints',
|
'updatePoints',
|
||||||
'handleError',
|
'handleError',
|
||||||
|
'toggleNightMode',
|
||||||
// used to hit the server
|
// used to hit the server
|
||||||
'hardGoTo',
|
'hardGoTo',
|
||||||
'delayedRedirect',
|
'delayedRedirect',
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
import { modernChallenges, map, challenges } from './challenges';
|
import { modernChallenges, map, challenges } from './challenges';
|
||||||
import NotFound from '../components/NotFound/index.jsx';
|
import NotFound from '../components/NotFound/index.jsx';
|
||||||
|
import { addLang } from '../utils/add-lang';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
path: '/:lang',
|
path: '/:lang',
|
||||||
|
indexRoute: {
|
||||||
|
onEnter(nextState, replace) {
|
||||||
|
const { lang } = nextState.params;
|
||||||
|
const { pathname } = nextState.location;
|
||||||
|
replace(addLang(pathname, lang));
|
||||||
|
}
|
||||||
|
},
|
||||||
childRoutes: [
|
childRoutes: [
|
||||||
challenges,
|
challenges,
|
||||||
modernChallenges,
|
modernChallenges,
|
||||||
|
@ -1,19 +1,7 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import supportedLanguages from '../../utils/supported-languages';
|
import { addLang } from './add-lang';
|
||||||
|
|
||||||
const toLowerCase = String.prototype.toLowerCase;
|
|
||||||
function addLang(url, lang) {
|
|
||||||
const maybeLang = toLowerCase.call(url.split('/')[1]);
|
|
||||||
if (supportedLanguages[maybeLang]) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
if (supportedLanguages[lang]) {
|
|
||||||
return `/${lang}${url}`;
|
|
||||||
}
|
|
||||||
return `/en${url}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({ lang: state.app.lang });
|
const mapStateToProps = state => ({ lang: state.app.lang });
|
||||||
|
|
||||||
|
13
common/app/utils/add-lang.js
Normal file
13
common/app/utils/add-lang.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import supportedLanguages from '../../utils/supported-languages';
|
||||||
|
|
||||||
|
const toLowerCase = String.prototype.toLowerCase;
|
||||||
|
export function addLang(url, lang) {
|
||||||
|
const maybeLang = toLowerCase.call(url.split('/')[1]);
|
||||||
|
if (supportedLanguages[maybeLang]) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
if (supportedLanguages[lang]) {
|
||||||
|
return `/${lang}${url}`;
|
||||||
|
}
|
||||||
|
return `/en${url}`;
|
||||||
|
}
|
@ -66,6 +66,7 @@
|
|||||||
"moment-timezone": "^0.5.0",
|
"moment-timezone": "^0.5.0",
|
||||||
"mongodb": "^2.0.33",
|
"mongodb": "^2.0.33",
|
||||||
"morgan": "^1.6.1",
|
"morgan": "^1.6.1",
|
||||||
|
"mousetrap": "^1.6.0",
|
||||||
"node-uuid": "^1.4.3",
|
"node-uuid": "^1.4.3",
|
||||||
"nodemailer": "^2.1.0",
|
"nodemailer": "^2.1.0",
|
||||||
"nodemailer-ses-transport": "^1.3.0",
|
"nodemailer-ses-transport": "^1.3.0",
|
||||||
|
Reference in New Issue
Block a user