Make the Web app aware of its context root

This commit is contained in:
Lyubomir Marinov 2017-02-04 20:29:24 -06:00
parent 23a0053dad
commit 8509efc8af
5 changed files with 111 additions and 33 deletions

View File

@ -203,10 +203,8 @@ function maybeRedirectToWelcomePage(options) {
// save whether current user is guest or not, before navigating // save whether current user is guest or not, before navigating
// to close page // to close page
window.sessionStorage.setItem('guest', APP.tokenData.isGuest); window.sessionStorage.setItem('guest', APP.tokenData.isGuest);
if (options.feedbackSubmitted) assignWindowLocationPathname(
window.location.pathname = "close.html"; options.feedbackSubmitted ? "close.html" : "close2.html");
else
window.location.pathname = "close2.html";
return; return;
} }
@ -219,11 +217,42 @@ function maybeRedirectToWelcomePage(options) {
if (config.enableWelcomePage) { if (config.enableWelcomePage) {
setTimeout(() => { setTimeout(() => {
APP.settings.setWelcomePageEnabled(true); APP.settings.setWelcomePageEnabled(true);
window.location.pathname = "/"; assignWindowLocationPathname('./');
}, 3000); }, 3000);
} }
} }
/**
* Assigns a specific pathname to window.location.pathname taking into account
* the context root of the Web app.
*
* @param {string} pathname - The pathname to assign to
* window.location.pathname. If the specified pathname is relative, the context
* root of the Web app will be prepended to the specified pathname before
* assigning it to window.location.pathname.
* @return {void}
*/
function assignWindowLocationPathname(pathname) {
const windowLocation = window.location;
if (!pathname.startsWith('/')) {
// XXX To support a deployment in a sub-directory, assume that the room
// (name) is the last non-directory component of the path (name).
let contextRoot = windowLocation.pathname;
contextRoot
= contextRoot.substring(0, contextRoot.lastIndexOf('/') + 1);
// A pathname equal to ./ specifies the current directory. It will be
// fine but pointless to include it because contextRoot is the current
// directory.
pathname.startsWith('./') && (pathname = pathname.substring(2));
pathname = contextRoot + pathname;
}
windowLocation.pathname = pathname;
}
/** /**
* Create local tracks of specified types. * Create local tracks of specified types.
* @param {Object} options * @param {Object} options
@ -323,7 +352,7 @@ class ConferenceConnector {
case ConferenceErrors.NOT_ALLOWED_ERROR: case ConferenceErrors.NOT_ALLOWED_ERROR:
{ {
// let's show some auth not allowed page // let's show some auth not allowed page
window.location.pathname = "authError.html"; assignWindowLocationPathname('authError.html');
} }
break; break;

View File

@ -38,7 +38,7 @@ export class AbstractApp extends Component {
} }
/** /**
* Initializes a new App instance. * Initializes a new AbstractApp instance.
* *
* @param {Object} props - The read-only React Component props with which * @param {Object} props - The read-only React Component props with which
* the new instance is to be initialized. * the new instance is to be initialized.
@ -334,13 +334,7 @@ export class AbstractApp extends Component {
// (2) A replace function would be provided to the Route in case it // (2) A replace function would be provided to the Route in case it
// chose to redirect to another path. // chose to redirect to another path.
this._onRouteEnter(route, nextState, pathname => { this._onRouteEnter(route, nextState, pathname => {
// FIXME In order to minimize the modifications related to the this._openURL(pathname);
// removal of react-router, the Web implementation is provided
// bellow because the replace function is used on Web only at the
// time of this writing. Provide a platform-agnostic implementation.
// It should likely find the best Route matching the specified
// pathname and navigate to it.
window.location.pathname = pathname;
// Do not proceed with the route because it chose to redirect to // Do not proceed with the route because it chose to redirect to
// another path. // another path.

View File

@ -14,6 +14,27 @@ export class App extends AbstractApp {
*/ */
static propTypes = AbstractApp.propTypes static propTypes = AbstractApp.propTypes
/**
* Initializes a new App instance.
*
* @param {Object} props - The read-only React Component props with which
* the new instance is to be initialized.
*/
constructor(props) {
super(props);
this.state = {
...this.state,
/**
* The context root of window.location i.e. this Web App.
*
* @type {string}
*/
windowLocationContextRoot: this._getWindowLocationContextRoot()
};
}
/** /**
* Inits the app before component will mount. * Inits the app before component will mount.
* *
@ -35,6 +56,22 @@ export class App extends AbstractApp {
return window.location; return window.location;
} }
/**
* Gets the context root of this Web App from window.location.
*
* @private
* @returns {string} The context root of window.location i.e. this Web App.
*/
_getWindowLocationContextRoot() {
const pathname = this._getWindowLocation().pathname;
const contextRootEndIndex = pathname.lastIndexOf('/');
return (
contextRootEndIndex === -1
? '/'
: pathname.substring(0, contextRootEndIndex + 1));
}
/** /**
* Navigates to a specific Route (via platform-specific means). * Navigates to a specific Route (via platform-specific means).
* *
@ -53,6 +90,7 @@ export class App extends AbstractApp {
= path.replace( = path.replace(
/:room/g, /:room/g,
store.getState()['features/base/conference'].room); store.getState()['features/base/conference'].room);
path = this._routePath2WindowLocationPathname(path);
// Navigate to the specified Route. // Navigate to the specified Route.
const windowLocation = this._getWindowLocation(); const windowLocation = this._getWindowLocation();
@ -69,4 +107,22 @@ export class App extends AbstractApp {
windowLocation.pathname = path; windowLocation.pathname = path;
} }
} }
/**
* Converts a specific Route path to a window.location.pathname.
*
* @param {string} path - A Route path to be converted to/represeted as a
* window.location.pathname.
* @private
* @returns {string} A window.location.pathname-compatible representation of
* the specified Route path.
*/
_routePath2WindowLocationPathname(path) {
let pathname = this.state.windowLocationContextRoot;
pathname.endsWith('/') || (pathname += '/');
pathname += path.startsWith('/') ? path.substring(1) : path;
return pathname;
}
} }

View File

@ -76,15 +76,18 @@ class WelcomePage extends AbstractWelcomePage {
} }
/** /**
* Returns the domain name. * Returns the URL of this WelcomePage for display purposes. For
* historic/legacy reasons, the return value is referred to as domain.
* *
* @private * @private
* @returns {string} Domain name. * @returns {string} The URL of this WelcomePage for display purposes.
*/ */
_getDomain() { _getDomain() {
const windowLocation = window.location; // As the returned URL is for display purposes, do not return the
// userinfo, query and fragment URI parts.
const wl = window.location;
return `${windowLocation.protocol}//${windowLocation.host}/`; return `${wl.protocol}//${wl.host}${wl.pathname}`;
} }
/** /**

View File

@ -10,26 +10,22 @@
* Builds and returns the room name. * Builds and returns the room name.
*/ */
function getRoomName () { // eslint-disable-line no-unused-vars function getRoomName () { // eslint-disable-line no-unused-vars
var getroomnode = config.getroomnode;
var path = window.location.pathname; var path = window.location.pathname;
var roomName; var roomName;
// determinde the room node from the url // Determine the room node from the URL.
// TODO: just the roomnode or the whole bare jid? if (getroomnode && typeof getroomnode === 'function') {
if (config.getroomnode && typeof config.getroomnode === 'function') {
// custom function might be responsible for doing the pushstate // custom function might be responsible for doing the pushstate
roomName = config.getroomnode(path); roomName = getroomnode.call(config, path);
} else { } else {
/* fall back to default strategy // Fall back to the default strategy of making assumptions about how the
* this is making assumptions about how the URL->room mapping happens. // URL maps to the room (name). It currently assumes a deployment in
* It currently assumes deployment at root, with a rewrite like the // which the last non-directory component of the path (name) is the
* following one (for nginx): // room.
location ~ ^/([a-zA-Z0-9]+)$ { roomName
rewrite ^/(.*)$ / break; = path.substring(path.lastIndexOf('/') + 1).toLowerCase()
} || undefined;
*/
if (path.length > 1) {
roomName = path.substr(1).toLowerCase();
}
} }
return roomName; return roomName;