| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- /*
- Copyright (C) 2017 Cloudbase Solutions SRL
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- import 'babel-polyfill';
- import ReactDOM from 'react-dom';
- import FastClick from 'fastclick';
- import Router from './routes';
- import Location from './core/Location';
- import { addEventListener, removeEventListener } from './core/DOMUtils';
- let cssContainer = document.getElementById('css');
- const appContainer = document.getElementById('app');
- const context = {
- insertCss: styles => styles._insertCss(),
- onSetTitle: value => (document.title = value),
- onSetMeta: (name, content) => {
- // Remove and create a new <meta /> tag in order to make it work
- // with bookmarks in Safari
- const elements = document.getElementsByTagName('meta');
- Array.from(elements).forEach((element) => {
- if (element.getAttribute('name') === name) {
- element.parentNode.removeChild(element);
- }
- });
- const meta = document.createElement('meta');
- meta.setAttribute('name', name);
- meta.setAttribute('content', content);
- document
- .getElementsByTagName('head')[0]
- .appendChild(meta);
- },
- };
- // Google Analytics tracking. Don't send 'pageview' event after the first
- // rendering, as it was already sent by the Html component.
- let trackPageview = () => (trackPageview = () => window.ga('send', 'pageview'));
- function render(state) {
- Router.dispatch(state, (newState, component) => {
- ReactDOM.render(component, appContainer, () => {
- // Restore the scroll position if it was saved into the state
- if (state.scrollY !== undefined) {
- window.scrollTo(state.scrollX, state.scrollY);
- } else {
- window.scrollTo(0, 0);
- }
- trackPageview();
- // Remove the pre-rendered CSS because it's no longer used
- // after the React app is launched
- if (cssContainer) {
- cssContainer.parentNode.removeChild(cssContainer);
- cssContainer = null;
- }
- });
- });
- }
- function run() {
- let currentLocation = null;
- let currentState = null;
- // Make taps on links and buttons work fast on mobiles
- FastClick.attach(document.body);
- // Re-render the app when window.location changes
- const unlisten = Location.listen(location => {
- currentLocation = location;
- currentState = Object.assign({}, location.state, {
- path: location.pathname,
- query: location.query,
- state: location.state,
- context,
- });
- render(currentState);
- });
- // Save the page scroll position into the current location's state
- const supportPageOffset = window.pageXOffset !== undefined;
- const isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat');
- const setPageOffset = () => {
- currentLocation.state = currentLocation.state || Object.create(null);
- if (supportPageOffset) {
- currentLocation.state.scrollX = window.pageXOffset;
- currentLocation.state.scrollY = window.pageYOffset;
- } else {
- currentLocation.state.scrollX = isCSS1Compat ?
- document.documentElement.scrollLeft : document.body.scrollLeft;
- currentLocation.state.scrollY = isCSS1Compat ?
- document.documentElement.scrollTop : document.body.scrollTop;
- }
- };
- addEventListener(window, 'scroll', setPageOffset);
- addEventListener(window, 'pagehide', () => {
- removeEventListener(window, 'scroll', setPageOffset);
- unlisten();
- });
- }
- // Run the application when both DOM is ready and page content is loaded
- if (['complete', 'loaded', 'interactive'].includes(document.readyState) && document.body) {
- run();
- } else {
- document.addEventListener('DOMContentLoaded', run, false);
- }
|