From 68a05653ea6f2588a27c8ce523b0d213e48f6480 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 8 Feb 2017 00:20:01 +0900 Subject: Add webapp/utils/url.jsx (#5285) webapp/utils/utils.jsx got big and that caused a potential circular dependency with webapp/stores/team_store.jsx. This change solves the issue by introducing webapp/utils/url.jsx and moving URL-related functions, which is not likely to depend on actions and stores, from webapp/utils/utils.jsx. --- webapp/actions/websocket_actions.jsx | 3 +- webapp/components/change_url_modal.jsx | 6 ++-- webapp/components/channel_header.jsx | 3 +- .../create_team/components/display_name.jsx | 4 +-- .../components/create_team/components/team_url.jsx | 7 ++-- .../components/installed_incoming_webhook.jsx | 4 +-- webapp/components/message_wrapper.jsx | 3 +- webapp/components/new_channel_flow.jsx | 3 +- .../post_view/components/post_message_view.jsx | 3 +- webapp/components/rename_channel_modal.jsx | 3 +- webapp/stores/team_store.jsx | 11 ++----- webapp/utils/url.jsx | 29 +++++++++++++++++ webapp/utils/utils.jsx | 38 ---------------------- 13 files changed, 54 insertions(+), 63 deletions(-) create mode 100644 webapp/utils/url.jsx (limited to 'webapp') diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx index 1a0ddda63..3f3e81d16 100644 --- a/webapp/actions/websocket_actions.jsx +++ b/webapp/actions/websocket_actions.jsx @@ -17,6 +17,7 @@ import WebSocketClient from 'client/web_websocket_client.jsx'; import * as WebrtcActions from './webrtc_actions.jsx'; import * as Utils from 'utils/utils.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; +import {getSiteURL} from 'utils/url.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; import {handleNewPost, loadPosts, loadProfilesForPosts} from 'actions/post_actions.jsx'; @@ -36,7 +37,7 @@ export function initialize() { return; } - let connUrl = Utils.getSiteURL(); + let connUrl = getSiteURL(); // replace the protocol with a websocket one if (connUrl.startsWith('https:')) { diff --git a/webapp/components/change_url_modal.jsx b/webapp/components/change_url_modal.jsx index ddbfdf83a..4abc469ea 100644 --- a/webapp/components/change_url_modal.jsx +++ b/webapp/components/change_url_modal.jsx @@ -5,7 +5,7 @@ import ReactDOM from 'react-dom'; import Constants from 'utils/constants.jsx'; import {Modal, Tooltip, OverlayTrigger} from 'react-bootstrap'; import TeamStore from 'stores/team_store.jsx'; -import * as Utils from 'utils/utils.jsx'; +import * as URL from 'utils/url.jsx'; import {FormattedMessage} from 'react-intl'; @@ -105,7 +105,7 @@ export default class ChangeUrlModal extends React.Component { e.preventDefault(); const url = ReactDOM.findDOMNode(this.refs.urlinput).value; - const cleanedURL = Utils.cleanUpUrlable(url); + const cleanedURL = URL.cleanUpUrlable(url); if (cleanedURL !== url || url.length < 2 || url.indexOf('__') > -1) { this.setState({urlError: this.getURLError(url)}); return; @@ -136,7 +136,7 @@ export default class ChangeUrlModal extends React.Component { } const fullTeamUrl = TeamStore.getCurrentTeamUrl(); - const teamURL = Utils.getShortenedTeamURL(TeamStore.getCurrentTeamUrl()); + const teamURL = URL.getShortenedTeamURL(TeamStore.getCurrentTeamUrl()); const urlTooltip = ( {fullTeamUrl} ); diff --git a/webapp/components/channel_header.jsx b/webapp/components/channel_header.jsx index e83d493f4..54e73cda5 100644 --- a/webapp/components/channel_header.jsx +++ b/webapp/components/channel_header.jsx @@ -28,6 +28,7 @@ import * as WebrtcActions from 'actions/webrtc_actions.jsx'; import * as ChannelActions from 'actions/channel_actions.jsx'; import * as Utils from 'utils/utils.jsx'; import * as ChannelUtils from 'utils/channel_utils.jsx'; +import {getSiteURL} from 'utils/url.jsx'; import * as TextFormatting from 'utils/text_formatting.jsx'; import {getFlaggedPosts} from 'actions/post_actions.jsx'; @@ -582,7 +583,7 @@ export default class ChannelHeader extends React.Component { let headerText; if (this.state.enableFormatting) { - headerText = TextFormatting.formatText(channel.header, {singleline: true, mentionHighlight: false, siteURL: Utils.getSiteURL()}); + headerText = TextFormatting.formatText(channel.header, {singleline: true, mentionHighlight: false, siteURL: getSiteURL()}); } else { headerText = channel.header; } diff --git a/webapp/components/create_team/components/display_name.jsx b/webapp/components/create_team/components/display_name.jsx index 67805a040..29077bd24 100644 --- a/webapp/components/create_team/components/display_name.jsx +++ b/webapp/components/create_team/components/display_name.jsx @@ -3,8 +3,8 @@ import {track} from 'actions/analytics_actions.jsx'; -import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; +import {cleanUpUrlable} from 'utils/url.jsx'; import logoImage from 'images/logo.png'; @@ -50,7 +50,7 @@ export default class TeamSignupDisplayNamePage extends React.Component { this.props.state.wizard = 'team_url'; this.props.state.team.display_name = displayName; - this.props.state.team.name = Utils.cleanUpUrlable(displayName); + this.props.state.team.name = cleanUpUrlable(displayName); this.props.updateParent(this.props.state); } diff --git a/webapp/components/create_team/components/team_url.jsx b/webapp/components/create_team/components/team_url.jsx index ccf5d63dc..4a063d145 100644 --- a/webapp/components/create_team/components/team_url.jsx +++ b/webapp/components/create_team/components/team_url.jsx @@ -1,11 +1,10 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import * as Utils from 'utils/utils.jsx'; - import {checkIfTeamExists, createTeam} from 'actions/team_actions.jsx'; import {track} from 'actions/analytics_actions.jsx'; import Constants from 'utils/constants.jsx'; +import * as URL from 'utils/url.jsx'; import logoImage from 'images/logo.png'; @@ -38,7 +37,7 @@ export default class TeamUrl extends React.Component { e.preventDefault(); const name = ReactDOM.findDOMNode(this.refs.name).value.trim(); - const cleanedName = Utils.cleanUpUrlable(name); + const cleanedName = URL.cleanUpUrlable(name); const urlRegex = /^[a-z]+([a-z\-0-9]+|(__)?)[a-z0-9]+$/g; if (!name) { @@ -136,7 +135,7 @@ export default class TeamUrl extends React.Component { nameDivClass += ' has-error'; } - const title = `${Utils.getSiteURL()}/`; + const title = `${URL.getSiteURL()}/`; const urlTooltip = ( {title} ); diff --git a/webapp/components/integrations/components/installed_incoming_webhook.jsx b/webapp/components/integrations/components/installed_incoming_webhook.jsx index 10328c605..9b4df2393 100644 --- a/webapp/components/integrations/components/installed_incoming_webhook.jsx +++ b/webapp/components/integrations/components/installed_incoming_webhook.jsx @@ -4,7 +4,7 @@ import React from 'react'; import ChannelStore from 'stores/channel_store.jsx'; -import * as Utils from 'utils/utils.jsx'; +import {getSiteURL} from 'utils/url.jsx'; import {FormattedMessage} from 'react-intl'; @@ -116,7 +116,7 @@ export default class InstalledIncomingWebhook extends React.Component { id='installed_integrations.url' defaultMessage='URL: {url}' values={{ - url: Utils.getSiteURL() + '/hooks/' + incomingWebhook.id + url: getSiteURL() + '/hooks/' + incomingWebhook.id }} /> diff --git a/webapp/components/message_wrapper.jsx b/webapp/components/message_wrapper.jsx index 4dba1024e..a79611e34 100644 --- a/webapp/components/message_wrapper.jsx +++ b/webapp/components/message_wrapper.jsx @@ -3,6 +3,7 @@ import * as TextFormatting from 'utils/text_formatting.jsx'; import * as Utils from 'utils/utils.jsx'; +import {getSiteURL} from 'utils/url.jsx'; import React from 'react'; @@ -15,7 +16,7 @@ export default class MessageWrapper extends React.Component { render() { if (this.props.message) { const options = Object.assign({}, this.props.options, { - siteURL: Utils.getSiteURL() + siteURL: getSiteURL() }); return ( diff --git a/webapp/components/new_channel_flow.jsx b/webapp/components/new_channel_flow.jsx index 539dd4d92..eb67c9cba 100644 --- a/webapp/components/new_channel_flow.jsx +++ b/webapp/components/new_channel_flow.jsx @@ -4,6 +4,7 @@ import * as Utils from 'utils/utils.jsx'; import TeamStore from 'stores/team_store.jsx'; import UserStore from 'stores/user_store.jsx'; +import {cleanUpUrlable} from 'utils/url.jsx'; import NewChannelModal from './new_channel_modal.jsx'; import ChangeURLModal from './change_url_modal.jsx'; @@ -165,7 +166,7 @@ class NewChannelFlow extends React.Component { channelHeader: data.header }); if (!this.state.nameModified) { - this.setState({channelName: Utils.cleanUpUrlable(data.displayName.trim())}); + this.setState({channelName: cleanUpUrlable(data.displayName.trim())}); } } render() { diff --git a/webapp/components/post_view/components/post_message_view.jsx b/webapp/components/post_view/components/post_message_view.jsx index 371dd64eb..2682b642e 100644 --- a/webapp/components/post_view/components/post_message_view.jsx +++ b/webapp/components/post_view/components/post_message_view.jsx @@ -8,6 +8,7 @@ import Constants from 'utils/constants.jsx'; import * as PostUtils from 'utils/post_utils.jsx'; import * as TextFormatting from 'utils/text_formatting.jsx'; import * as Utils from 'utils/utils.jsx'; +import {getSiteURL} from 'utils/url.jsx'; import {renderSystemMessage} from './system_message_helpers.jsx'; @@ -103,7 +104,7 @@ export default class PostMessageView extends React.Component { const options = Object.assign({}, this.props.options, { emojis: this.props.emojis, - siteURL: Utils.getSiteURL(), + siteURL: getSiteURL(), mentionKeys: this.props.mentionKeys, usernameMap: this.props.usernameMap, channelNamesMap: this.props.channelNamesMap, diff --git a/webapp/components/rename_channel_modal.jsx b/webapp/components/rename_channel_modal.jsx index 5253b1c80..9e2cfd8d8 100644 --- a/webapp/components/rename_channel_modal.jsx +++ b/webapp/components/rename_channel_modal.jsx @@ -4,6 +4,7 @@ import ReactDOM from 'react-dom'; import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; +import {cleanUpUrlable} from 'utils/url.jsx'; import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl'; import {updateChannel} from 'actions/channel_actions.jsx'; @@ -145,7 +146,7 @@ export class RenameChannelModal extends React.Component { state.nameError = formatMessage(holders.maxLength); state.invalid = true; } else { - const cleanedName = Utils.cleanUpUrlable(channel.name); + const cleanedName = cleanUpUrlable(channel.name); if (cleanedName === channel.name) { state.nameError = ''; } else { diff --git a/webapp/stores/team_store.jsx b/webapp/stores/team_store.jsx index 6de47c65c..2752c6b57 100644 --- a/webapp/stores/team_store.jsx +++ b/webapp/stores/team_store.jsx @@ -6,6 +6,7 @@ import EventEmitter from 'events'; import UserStore from 'stores/user_store.jsx'; import Constants from 'utils/constants.jsx'; +import {getSiteURL} from 'utils/url.jsx'; const ActionTypes = Constants.ActionTypes; const CHANGE_EVENT = 'change'; @@ -122,10 +123,7 @@ class TeamStoreClass extends EventEmitter { const current = this.getCurrent(); if (current) { - // can't call Utils.getSiteURL here because that introduces a circular dependency - const origin = window.mm_config.SiteURL || window.location.origin; - - return origin + '/signup_user_complete/?id=' + current.invite_id; + return getSiteURL() + '/signup_user_complete/?id=' + current.invite_id; } return ''; @@ -138,10 +136,7 @@ class TeamStoreClass extends EventEmitter { return ''; } - // can't call Utils.getSiteURL here because that introduces a circular dependency - const origin = window.mm_config.SiteURL || window.location.origin; - - return origin + '/' + team.name; + return getSiteURL() + '/' + team.name; } getCurrentStats() { diff --git a/webapp/utils/url.jsx b/webapp/utils/url.jsx new file mode 100644 index 000000000..9fe00da6f --- /dev/null +++ b/webapp/utils/url.jsx @@ -0,0 +1,29 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +export function cleanUpUrlable(input) { + var cleaned = input.trim().replace(/-/g, ' ').replace(/[^\w\s]/gi, '').toLowerCase().replace(/\s/g, '-'); + cleaned = cleaned.replace(/-{2,}/, '-'); + cleaned = cleaned.replace(/^-+/, ''); + cleaned = cleaned.replace(/-+$/, ''); + return cleaned; +} + +export function getShortenedTeamURL(teamURL = '') { + if (teamURL.length > 35) { + return teamURL.substring(0, 10) + '...' + teamURL.substring(teamURL.length - 12, teamURL.length) + '/'; + } + return teamURL + '/'; +} + +export function getSiteURL() { + if (global.mm_config.SiteURL) { + return global.mm_config.SiteURL; + } + + if (window.location.origin) { + return window.location.origin; + } + + return window.location.protocol + '//' + window.location.hostname + (window.location.port ? ':' + window.location.port : ''); +} diff --git a/webapp/utils/utils.jsx b/webapp/utils/utils.jsx index 90e2ad63e..c639abc56 100644 --- a/webapp/utils/utils.jsx +++ b/webapp/utils/utils.jsx @@ -27,14 +27,6 @@ export function isEmail(email) { return (/^.+@.+$/).test(email); } -export function cleanUpUrlable(input) { - var cleaned = input.trim().replace(/-/g, ' ').replace(/[^\w\s]/gi, '').toLowerCase().replace(/\s/g, '-'); - cleaned = cleaned.replace(/-{2,}/, '-'); - cleaned = cleaned.replace(/^-+/, ''); - cleaned = cleaned.replace(/-+$/, ''); - return cleaned; -} - export function isMac() { return navigator.platform.toUpperCase().indexOf('MAC') >= 0; } @@ -996,17 +988,6 @@ export function fileSizeToString(bytes) { return bytes + 'B'; } -// Converts a filename (like those attached to Post objects) to a url that can be used to retrieve attachments from the server. -export function getFileUrl(filename) { - return Client.getFilesRoute() + '/get' + filename; -} - -// Gets the name of a file (including extension) from a given url or file path. -export function getFileName(path) { - var split = path.split('/'); - return split[split.length - 1]; -} - // Gets the websocket port to use. Configurable on the server. export function getWebsocketPort(protocol) { if ((/^wss:/).test(protocol)) { // wss:// @@ -1078,13 +1059,6 @@ export function importSlack(file, success, error) { Client.importSlack(formData, success, error); } -export function getShortenedTeamURL(teamURL = '') { - if (teamURL.length > 35) { - return teamURL.substring(0, 10) + '...' + teamURL.substring(teamURL.length - 12, teamURL.length) + '/'; - } - return teamURL + '/'; -} - export function windowWidth() { return $(window).width(); } @@ -1274,18 +1248,6 @@ export function isValidPassword(password) { return errorMsg; } -export function getSiteURL() { - if (global.mm_config.SiteURL) { - return global.mm_config.SiteURL; - } - - if (window.location.origin) { - return window.location.origin; - } - - return window.location.protocol + '//' + window.location.hostname + (window.location.port ? ':' + window.location.port : ''); -} - export function handleFormattedTextClick(e) { const mentionAttribute = e.target.getAttributeNode('data-mention'); const hashtagAttribute = e.target.getAttributeNode('data-hashtag'); -- cgit v1.2.3-1-g7c22