provide-page
Version:
Provides automatic server-side rendering and actions (regardless of whether or not client has JavaScript enabled) to React components. Use in conjunction with `provide-router`.
637 lines (510 loc) • 20.3 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.NOOP = exports.DESTROY_SESSION = exports.UPDATE_SESSION = exports.PENDING_FORM = exports.PENDING_PAGE = exports.SUBMITTED_FORM = exports.SUBMIT_FORM = exports.SUBMIT_REQUEST = exports.GOT_PAGE_STATES = exports.GET_PAGE_STATES = exports.SYNC_WITH_ROUTER = exports.SET_REQUEST_ERROR = exports.SET_JS_FILES = exports.SET_CSS_FILES = exports.SET_ICON_FILE = exports.SET_META_ROBOTS = exports.SET_META_DESCRIPTION = exports.SET_DOCUMENT_TITLE = exports.SET_STATUS_CODE = exports.SET_HEADERS = exports.defaultRenderDocumentToString = exports.createMiddleware = exports.Form = exports.Link = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _reduxThunk = require('redux-thunk');
var _reduxThunk2 = _interopRequireDefault(_reduxThunk);
var _exenv = require('exenv');
var _Link2 = require('./components/Link');
var _Link3 = _interopRequireDefault(_Link2);
var _Form2 = require('./components/Form');
var _Form3 = _interopRequireDefault(_Form2);
var _createMiddleware2 = require('./createMiddleware');
var _createMiddleware3 = _interopRequireDefault(_createMiddleware2);
var _defaultRenderDocumentToString2 = require('./defaultRenderDocumentToString');
var _defaultRenderDocumentToString3 = _interopRequireDefault(_defaultRenderDocumentToString2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.Link = _Link3.default;
exports.Form = _Form3.default;
exports.createMiddleware = _createMiddleware3.default;
exports.defaultRenderDocumentToString = _defaultRenderDocumentToString3.default;
var SET_HEADERS = exports.SET_HEADERS = 'SET_HEADERS';
var SET_STATUS_CODE = exports.SET_STATUS_CODE = 'SET_STATUS_CODE';
var SET_DOCUMENT_TITLE = exports.SET_DOCUMENT_TITLE = 'SET_DOCUMENT_TITLE';
var SET_META_DESCRIPTION = exports.SET_META_DESCRIPTION = 'SET_META_DESCRIPTION';
var SET_META_ROBOTS = exports.SET_META_ROBOTS = 'SET_META_ROBOTS';
var SET_ICON_FILE = exports.SET_ICON_FILE = 'SET_ICON_FILE';
var SET_CSS_FILES = exports.SET_CSS_FILES = 'SET_CSS_FILES';
var SET_JS_FILES = exports.SET_JS_FILES = 'SET_JS_FILES';
var SET_REQUEST_ERROR = exports.SET_REQUEST_ERROR = 'SET_REQUEST_ERROR';
var SYNC_WITH_ROUTER = exports.SYNC_WITH_ROUTER = 'SYNC_WITH_ROUTER';
var GET_PAGE_STATES = exports.GET_PAGE_STATES = 'GET_PAGE_STATES';
var GOT_PAGE_STATES = exports.GOT_PAGE_STATES = 'GOT_PAGE_STATES';
var SUBMIT_REQUEST = exports.SUBMIT_REQUEST = 'SUBMIT_REQUEST';
var SUBMIT_FORM = exports.SUBMIT_FORM = 'SUBMIT_FORM';
var SUBMITTED_FORM = exports.SUBMITTED_FORM = 'SUBMITTED_FORM';
var PENDING_PAGE = exports.PENDING_PAGE = 'PENDING_PAGE';
var PENDING_FORM = exports.PENDING_FORM = 'PENDING_FORM';
var UPDATE_SESSION = exports.UPDATE_SESSION = 'UPDATE_SESSION';
var DESTROY_SESSION = exports.DESTROY_SESSION = 'DESTROY_SESSION';
var NOOP = exports.NOOP = 'NOOP';
function getUrl(location) {
return location ? location.pathname + location.search : null;
}
function clearPending(dispatch, getState) {
var state = getState();
if (state.pendingForms.length) {
var _state$pendingForms$s = state.pendingForms.shift(),
formData = _state$pendingForms$s.formData,
onSubmit = _state$pendingForms$s.onSubmit;
dispatch(actions.submitForm(formData, onSubmit));
} else if (state.pendingPage) {
dispatch(actions.getPageStates(typeof window === 'undefined' ? state.routerLocation : window.location));
}
}
var _noEffect = true;
var batchAction = function batchAction(action, immediate) {
if (immediate) {
return action;
}
return function (dispatch, getState) {
var type = action.type;
var _getState = getState(),
pageBatchedActions = _getState.pageBatchedActions;
var timeout = setTimeout(function () {
while (pageBatchedActions[type].count) {
pageBatchedActions[type].count--;
dispatch({ type: NOOP, _noEffect: _noEffect });
}
delete pageBatchedActions[type];
dispatch(action);
});
if (pageBatchedActions[type]) {
clearTimeout(pageBatchedActions[type].timeout);
pageBatchedActions[type].timeout = timeout;
pageBatchedActions[type].count++;
} else {
pageBatchedActions[type] = { timeout: timeout, count: 0 };
}
};
};
var actions = {
setHeaders: function setHeaders(headers, immediate) {
return batchAction({ type: SET_HEADERS, headers: headers, _noEffect: _noEffect }, immediate);
},
setStatusCode: function setStatusCode(statusCode, immediate) {
return batchAction({ type: SET_STATUS_CODE, statusCode: statusCode, _noEffect: _noEffect }, immediate);
},
setDocumentTitle: function setDocumentTitle() {
var documentTitle = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var immediate = arguments[1];
return batchAction({ type: SET_DOCUMENT_TITLE, documentTitle: documentTitle, _noEffect: _noEffect }, immediate);
},
setMetaDescription: function setMetaDescription() {
var metaDescription = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var immediate = arguments[1];
return batchAction({ type: SET_META_DESCRIPTION, metaDescription: metaDescription, _noEffect: _noEffect }, immediate);
},
setMetaRobots: function setMetaRobots() {
var metaRobots = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var immediate = arguments[1];
return batchAction({ type: SET_META_ROBOTS, metaRobots: metaRobots, _noEffect: _noEffect }, immediate);
},
setIconFile: function setIconFile() {
var iconFile = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var immediate = arguments[1];
return batchAction({ type: SET_ICON_FILE, iconFile: iconFile, _noEffect: _noEffect }, immediate);
},
setCssFiles: function setCssFiles() {
var cssFiles = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var immediate = arguments[1];
return batchAction({ type: SET_CSS_FILES, cssFiles: cssFiles, _noEffect: _noEffect }, immediate);
},
setJsFiles: function setJsFiles() {
var jsFiles = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var immediate = arguments[1];
return batchAction({ type: SET_JS_FILES, jsFiles: jsFiles, _noEffect: _noEffect }, immediate);
},
setRequestError: function setRequestError(requestError, immediate) {
return batchAction({ type: SET_REQUEST_ERROR, requestError: requestError }, immediate);
},
syncWithRouter: function syncWithRouter(routerHistory, routerLocation) {
return function (dispatch, getState) {
dispatch({
type: SYNC_WITH_ROUTER, routerHistory: routerHistory, routerLocation: routerLocation, _noEffect: _noEffect
});
routerHistory.listen(function (nextRouterLocation) {
dispatch(actions.getPageStates(nextRouterLocation));
});
};
},
getPageStates: function getPageStates(routerLocation) {
return function (dispatch, getState, _ref) {
var setStates = _ref.setStates;
var _getState2 = getState(),
ssrDisabled = _getState2.ssrDisabled,
waitingForResponse = _getState2.waitingForResponse,
routerHistory = _getState2.routerHistory;
if (ssrDisabled === true || typeof XMLHttpRequest === 'undefined') {
dispatch({ type: NOOP, _noEffect: _noEffect });
return;
}
if (waitingForResponse) {
dispatch({ type: PENDING_PAGE, routerLocation: routerLocation, _noEffect: _noEffect });
return;
}
var xhr = new XMLHttpRequest();
var headers = {
'content-type': 'application/json;charset=UTF-8',
'accept': 'application/json'
};
dispatch({ type: GET_PAGE_STATES, routerLocation: routerLocation, _noEffect: _noEffect });
xhr.open('GET', getUrl(routerLocation), true);
for (var header in headers) {
xhr.setRequestHeader(header, headers[header]);
}
xhr.onload = function () {
var states = JSON.parse(xhr.response);
setStates(states);
dispatch({ type: GOT_PAGE_STATES, states: states });
clearPending(dispatch, getState);
};
xhr.send();
};
},
submitRequest: function submitRequest(_ref2) {
var _ref2$requestMethod = _ref2.requestMethod,
requestMethod = _ref2$requestMethod === undefined ? 'POST' : _ref2$requestMethod,
_ref2$requestBody = _ref2.requestBody,
requestBody = _ref2$requestBody === undefined ? {} : _ref2$requestBody,
_ref2$requestHeaders = _ref2.requestHeaders,
requestHeaders = _ref2$requestHeaders === undefined ? {} : _ref2$requestHeaders,
requestSession = _ref2.requestSession,
acceptJson = _ref2.acceptJson;
return {
type: SUBMIT_REQUEST,
requestMethod: requestMethod,
requestBody: requestBody,
requestHeaders: requestHeaders,
requestSession: requestSession,
acceptJson: acceptJson
};
},
submitForm: function submitForm(formData, onSubmit) {
return function (dispatch, getState, _ref3) {
var setStates = _ref3.setStates;
var _getState3 = getState(),
ssrDisabled = _getState3.ssrDisabled,
waitingForResponse = _getState3.waitingForResponse,
routerLocation = _getState3.routerLocation;
if (ssrDisabled === true || typeof XMLHttpRequest === 'undefined') {
formData._formHandled = true;
if (onSubmit) {
onSubmit(null, formData);
}
dispatch({ type: NOOP, _noEffect: _noEffect });
return;
}
if (waitingForResponse) {
dispatch({ type: PENDING_FORM, formData: formData, onSubmit: onSubmit, _noEffect: _noEffect });
return;
}
var xhr = new XMLHttpRequest();
var headers = {
'content-type': 'application/json;charset=UTF-8',
'accept': 'application/json'
};
if (onSubmit) {
headers['x-server-side'] = true;
}
dispatch({ type: SUBMIT_FORM, formData: formData, onSubmit: onSubmit });
xhr.open('POST', getUrl(routerLocation), true);
for (var header in headers) {
xhr.setRequestHeader(header, headers[header]);
}
xhr.onload = function () {
var states = JSON.parse(xhr.response);
formData._formHandled = true;
setStates(states);
if (onSubmit) {
onSubmit(null, formData);
}
dispatch({ type: SUBMITTED_FORM, formData: formData, onSubmit: onSubmit, states: states });
clearPending(dispatch, getState);
};
xhr.send(JSON.stringify(formData));
};
},
updateSession: function updateSession(updates, immediate) {
return batchAction({ type: UPDATE_SESSION, updates: updates }, immediate);
},
destroySession: function destroySession(immediate) {
return batchAction({ type: DESTROY_SESSION }, immediate);
}
};
var reducers = {
headers: function headers() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var action = arguments[1];
switch (action.type) {
case SET_HEADERS:
return action.headers;
default:
return state;
}
},
statusCode: function statusCode() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var action = arguments[1];
switch (action.type) {
case SET_STATUS_CODE:
return action.statusCode;
default:
return state;
}
},
documentTitle: function documentTitle() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _exenv.canUseDOM && document.title;
var action = arguments[1];
switch (action.type) {
case SET_DOCUMENT_TITLE:
if (_exenv.canUseDOM) {
document.title = action.documentTitle;
}
return action.documentTitle;
default:
return state;
}
},
metaDescription: function metaDescription() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'Built with provide-page.';
var action = arguments[1];
switch (action.type) {
case SET_META_DESCRIPTION:
return action.metaDescription;
default:
return state;
}
},
metaRobots: function metaRobots() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'index,follow';
var action = arguments[1];
switch (action.type) {
case SET_META_ROBOTS:
return action.metaRobots;
default:
return state;
}
},
iconFile: function iconFile() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '/static/favicon.ico';
var action = arguments[1];
switch (action.type) {
case SET_ICON_FILE:
return action.iconFile;
default:
return state;
}
},
cssFiles: function cssFiles() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var action = arguments[1];
switch (action.type) {
case SET_CSS_FILES:
return action.cssFiles;
default:
return state;
}
},
jsFiles: function jsFiles() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var action = arguments[1];
switch (action.type) {
case SET_JS_FILES:
return action.jsFiles;
default:
return state;
}
},
requestError: function requestError() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var action = arguments[1];
switch (action.type) {
case SET_REQUEST_ERROR:
return action.requestError;
default:
return state;
}
},
requestSession: function requestSession() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var action = arguments[1];
if (!state.__actualSession && typeof state.destroy !== 'undefined') {
state = _extends({}, state, { __actualSession: state });
}
switch (action.type) {
case SUBMIT_REQUEST:
var requestSession = action.requestSession;
return requestSession ? _extends({}, requestSession, { __actualSession: requestSession }) : state;
case UPDATE_SESSION:
var nextState = _extends({}, state);
var _action$updates = action.updates,
updates = _action$updates === undefined ? {} : _action$updates;
delete updates.__actualSession; // just in case
if (!nextState.__actualSession) {
nextState.__actualSession = {};
}
for (var key in updates) {
nextState[key] = updates[key];
nextState.__actualSession[key] = updates[key];
}
if (nextState.__actualSession.save) {
nextState.__actualSession.save();
}
return nextState;
case DESTROY_SESSION:
if (state.__actualSession && state.__actualSession.destroy) {
state.__actualSession.destroy();
return { __actualSession: state.__actualSession };
}
return { __actualSession: {} };
default:
return state;
}
},
requestMethod: function requestMethod() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var action = arguments[1];
switch (action.type) {
case SUBMIT_REQUEST:
return action.requestMethod;
default:
return state;
}
},
requestBody: function requestBody() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var action = arguments[1];
switch (action.type) {
case SUBMIT_FORM:
return action.formData;
case SUBMIT_REQUEST:
return action.requestBody;
default:
return state;
}
},
requestHeaders: function requestHeaders() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var action = arguments[1];
switch (action.type) {
case SUBMIT_FORM:
case SUBMIT_REQUEST:
return action.requestHeaders || {};
default:
return state;
}
},
acceptJson: function acceptJson() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var action = arguments[1];
switch (action.type) {
case SUBMIT_REQUEST:
return typeof action.acceptJson === 'undefined' ? state : action.acceptJson;
default:
return state;
}
},
routerHistory: function routerHistory() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var action = arguments[1];
switch (action.type) {
case SYNC_WITH_ROUTER:
return action.routerHistory;
default:
return state;
}
},
routerLocation: function routerLocation() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var action = arguments[1];
switch (action.type) {
case SYNC_WITH_ROUTER:
case GET_PAGE_STATES:
return action.routerLocation;
default:
return state;
}
},
waitingForResponse: function waitingForResponse() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var action = arguments[1];
switch (action.type) {
case GET_PAGE_STATES:
case SUBMIT_FORM:
return true;
case GOT_PAGE_STATES:
case SUBMITTED_FORM:
return false;
default:
return state;
}
},
pendingPage: function pendingPage() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var action = arguments[1];
switch (action.type) {
case PENDING_PAGE:
return true;
case GET_PAGE_STATES:
case SUBMIT_FORM:
return false;
default:
return state;
}
},
pendingForms: function pendingForms() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var _ref4 = arguments[1];
var type = _ref4.type,
formData = _ref4.formData,
onSubmit = _ref4.onSubmit;
if (type === PENDING_FORM) {
state.push({ formData: formData, onSubmit: onSubmit });
}
return state;
},
pageBatchedActions: function pageBatchedActions() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return state;
},
ssrDisabled: function ssrDisabled() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
return state;
}
};
var merge = {
formData: {
keys: ['requestBody'],
get: function get(_ref5, _ref6) {
var requestBody = _ref5.requestBody;
var formId = _ref6.formId;
return requestBody && requestBody._formId === formId ? requestBody : null;
}
}
};
var middleware = _reduxThunk2.default;
var clientStateKeys = ['requestSession', 'requestError'];
var subscribeTo = {
router: function router(_ref7, _ref8) {
var routerStore = _ref7.store;
var pageStore = _ref8.store;
// there's probably a better way to do this but whatever
var _pageStore$getState = pageStore.getState(),
routerHistory = _pageStore$getState.routerHistory;
if (typeof window !== 'undefined' && !routerHistory) {
var _routerStore$getState = routerStore.getState(),
history = _routerStore$getState.history,
routing = _routerStore$getState.routing;
var location = routing && routing.locationBeforeTransitions || routing && routing.location || routerStore.getState().location || history.location;
if (history && location) {
pageStore.dispatch(actions.syncWithRouter(history, location));
}
}
}
};
exports.default = {
actions: actions, reducers: reducers, merge: merge, middleware: middleware, clientStateKeys: clientStateKeys, subscribeTo: subscribeTo
};