Skip to content

Commit

Permalink
Add AJAX navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
Saluev committed Mar 9, 2019
1 parent 648f1a3 commit 168def1
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 24 deletions.
11 changes: 2 additions & 9 deletions frontend/src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,16 @@ import {render} from 'react-dom'
import {Provider} from 'react-redux'
import App from './components/app'
import configureStore from './redux/configureStore'
import {navigate} from "./redux/actions";

let initialState = {
page: {
type: "home"
}
};
const m = /^\/card\/([^\/]+)$/.exec(location.pathname);
if (m !== null) {
initialState = {
page: {
type: "card",
cardSlug: m[1]
},
}
}

const store = configureStore(initialState);
store.dispatch(navigate(location));

render(
<Provider store={store}>
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,26 @@ import React, {Component} from 'react'
import {connect} from "react-redux";

import CardPage from "./cardPage"
import {navigate} from "../redux/actions";

class App extends Component {

componentDidMount() {
history.replaceState({
pathname: location.pathname,
href: location.href
}, "");
window.addEventListener("popstate", event => this.navigate(event));
}

navigate(event) {
if (event.state && event.state.pathname) {
event.preventDefault();
event.stopPropagation();
this.props.dispatch(navigate(event.state, true));
}
}

render() {
const {pageType} = this.props;
return (
Expand Down
17 changes: 15 additions & 2 deletions frontend/src/components/card.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import React, {Component} from 'react';
import {connect} from "react-redux";
import {navigate} from "../redux/actions";

class Card extends Component {

componentDidMount() {
document.title = this.props.name
}

navigate(event) {
if (event.target.tagName === 'A'
&& event.target.hostname === window.location.hostname) {
event.preventDefault();
this.props.dispatch(navigate(event.target));
}
}

render() {
const {name, html} = this.props;
return (
<div>
<h1>{name}</h1>
<div dangerouslySetInnerHTML={{__html: html}}/>
<div
dangerouslySetInnerHTML={{__html: html}}
onClick={event => this.navigate(event)}
/>
</div>
);
}

}

export default Card;
export default connect()(Card);
4 changes: 4 additions & 0 deletions frontend/src/components/cardPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ class CardPage extends Component {
this.props.dispatch(fetchCardIfNeeded())
}

componentDidUpdate(prevProps, prevState, snapshot) {
this.props.dispatch(fetchCardIfNeeded())
}

render() {
const {isFetching, cardData} = this.props;
return (
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/redux/actions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const START_FETCHING_CARD = "START_FETCHING_CARD";
export const FINISH_FETCHING_CARD = "FINISH_FETCHING_CARD";
export const NAVIGATE = "NAVIGATE";

function apiPath() {
return "http://localhost:40001/api/v1";
Expand Down Expand Up @@ -36,3 +37,16 @@ export function fetchCardIfNeeded() {
}
};
}

export function navigate(link, dontPushState) {
if (!dontPushState) {
history.pushState({
pathname: link.pathname,
href: link.href
}, "", link.href);
}
return {
type: NAVIGATE,
path: link.pathname
}
}
22 changes: 20 additions & 2 deletions frontend/src/redux/reducers.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
import {
START_FETCHING_CARD,
FINISH_FETCHING_CARD
FINISH_FETCHING_CARD,
NAVIGATE
} from "./actions";

function navigate(state, path) {
let m = /^\/card\/([^/]+)$/.exec(path);
if (m !== null) {
return {
...state,
page: {
type: "card",
cardSlug: m[1],
isFetching: true
}
};
}
return state
}

export default function root(state = {}, action) {
switch (action.type) {
case START_FETCHING_CARD:
Expand All @@ -21,7 +37,9 @@ export default function root(state = {}, action) {
isFetching: false,
cardData: action.cardData
}
}
};
case NAVIGATE:
return navigate(state, action.path)
}
return state;
}
37 changes: 26 additions & 11 deletions tools/add_test_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,30 @@

wiring = Wiring()

try:
card = wiring.card_dao.get_by_slug("helloworld")
except CardNotFound:
card = wiring.card_dao.create(Card(
slug="helloworld",
name="Hello, world!",
markdown="""
This is a hello-world page.
"""))

wiring.task_queue.enqueue_call(
parse_card_markup, kwargs={"card_id": card.id})
def create_or_update(card):
try:
card.id = wiring.card_dao.get_by_slug(card.slug).id
card = wiring.card_dao.update(card)
except CardNotFound:
card = wiring.card_dao.create(card)
wiring.task_queue.enqueue_call(
parse_card_markup, kwargs={"card_id": card.id})


create_or_update(Card(
slug="helloworld",
name="Hello, world!",
markdown="""
This is a hello-world page. It can't really compete with the [demo page](demo).
"""))

create_or_update(Card(
slug="demo",
name="Demo Card!",
markdown="""
Hi there, habrovchanin. You've probably got here from the awkward ["Hello, world" card](helloworld).
Well, **good news**! Finally you are looking at a **really cool card**!
"""
))

0 comments on commit 168def1

Please sign in to comment.