PLT-1236 Added special handling for markdown links within mattermost (#2763)
* Added special handling for markdown links within mattermost * Moved application of .app__body class to route components
Этот коммит содержится в:
коммит произвёл
Corey Hulen
родитель
e80bf13f48
Коммит
f73daebb61
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
import $ from 'jquery';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import ChannelHeader from 'components/channel_header.jsx';
|
import ChannelHeader from 'components/channel_header.jsx';
|
||||||
@@ -35,9 +36,13 @@ export default class ChannelView extends React.Component {
|
|||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
ChannelStore.addChangeListener(this.updateState);
|
ChannelStore.addChangeListener(this.updateState);
|
||||||
|
|
||||||
|
$('body').addClass('app__body');
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
ChannelStore.removeChangeListener(this.updateState);
|
ChannelStore.removeChangeListener(this.updateState);
|
||||||
|
|
||||||
|
$('body').removeClass('app__body');
|
||||||
}
|
}
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
this.setState(this.getStateFromStores(nextProps));
|
this.setState(this.getStateFromStores(nextProps));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
import $ from 'jquery';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import ChannelHeader from 'components/channel_header.jsx';
|
import ChannelHeader from 'components/channel_header.jsx';
|
||||||
@@ -45,10 +46,14 @@ export default class PermalinkView extends React.Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
ChannelStore.addChangeListener(this.updateState);
|
ChannelStore.addChangeListener(this.updateState);
|
||||||
TeamStore.addChangeListener(this.updateState);
|
TeamStore.addChangeListener(this.updateState);
|
||||||
|
|
||||||
|
$('body').addClass('app__body');
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
ChannelStore.removeChangeListener(this.updateState);
|
ChannelStore.removeChangeListener(this.updateState);
|
||||||
TeamStore.removeChangeListener(this.updateState);
|
TeamStore.removeChangeListener(this.updateState);
|
||||||
|
|
||||||
|
$('body').removeClass('app__body');
|
||||||
}
|
}
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
this.setState(this.getStateFromStores(nextProps));
|
this.setState(this.getStateFromStores(nextProps));
|
||||||
|
|||||||
@@ -379,13 +379,11 @@ export default class PostsView extends React.Component {
|
|||||||
}
|
}
|
||||||
window.addEventListener('resize', this.handleResize);
|
window.addEventListener('resize', this.handleResize);
|
||||||
PreferenceStore.addChangeListener(this.updateState);
|
PreferenceStore.addChangeListener(this.updateState);
|
||||||
$('body').addClass('app__body');
|
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
window.removeEventListener('resize', this.handleResize);
|
window.removeEventListener('resize', this.handleResize);
|
||||||
this.scrollStopAction.cancel();
|
this.scrollStopAction.cancel();
|
||||||
PreferenceStore.removeChangeListener(this.updateState);
|
PreferenceStore.removeChangeListener(this.updateState);
|
||||||
$('body').removeClass('app__body');
|
|
||||||
}
|
}
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
if (this.props.postList != null) {
|
if (this.props.postList != null) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import $ from 'jquery';
|
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
import TeamStore from 'stores/team_store.jsx';
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
import PreferenceStore from 'stores/preference_store.jsx';
|
import PreferenceStore from 'stores/preference_store.jsx';
|
||||||
@@ -35,12 +34,6 @@ export default class TutorialIntroScreens extends React.Component {
|
|||||||
|
|
||||||
this.state = {currentScreen: 0};
|
this.state = {currentScreen: 0};
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
|
||||||
$('body').addClass('app__body');
|
|
||||||
}
|
|
||||||
componentWillUnmount() {
|
|
||||||
$('body').removeClass('app__body');
|
|
||||||
}
|
|
||||||
handleNext() {
|
handleNext() {
|
||||||
if (this.state.currentScreen < 2) {
|
if (this.state.currentScreen < 2) {
|
||||||
this.setState({currentScreen: this.state.currentScreen + 1});
|
this.setState({currentScreen: this.state.currentScreen + 1});
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import TutorialIntroScreens from './tutorial_intro_screens.jsx';
|
|||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
|
import $ from 'jquery';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default class TutorialView extends React.Component {
|
export default class TutorialView extends React.Component {
|
||||||
@@ -20,9 +21,13 @@ export default class TutorialView extends React.Component {
|
|||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
ChannelStore.addChangeListener(this.handleChannelChange);
|
ChannelStore.addChangeListener(this.handleChannelChange);
|
||||||
|
|
||||||
|
$('body').addClass('app__body');
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
ChannelStore.removeChangeListener(this.handleChannelChange);
|
ChannelStore.removeChangeListener(this.handleChannelChange);
|
||||||
|
|
||||||
|
$('body').removeClass('app__body');
|
||||||
}
|
}
|
||||||
handleChannelChange() {
|
handleChannelChange() {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import * as TextFormatting from './text_formatting.jsx';
|
import * as TextFormatting from './text_formatting.jsx';
|
||||||
import * as Utils from './utils.jsx';
|
|
||||||
import * as syntaxHightlighting from './syntax_hightlighting.jsx';
|
import * as syntaxHightlighting from './syntax_hightlighting.jsx';
|
||||||
|
|
||||||
import marked from 'marked';
|
import marked from 'marked';
|
||||||
@@ -137,18 +136,20 @@ class MattermostMarkdownRenderer extends marked.Renderer {
|
|||||||
outHref = `http://${outHref}`;
|
outHref = `http://${outHref}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = '<a class="theme markdown__link" href="' + outHref + '"';
|
let output = '<a class="theme markdown__link" ';
|
||||||
|
|
||||||
|
// special case for links that are inside the app
|
||||||
|
if (outHref.startsWith(global.location.origin)) {
|
||||||
|
output += 'data-link="' + outHref.substring(global.location.origin.length) + '"';
|
||||||
|
} else {
|
||||||
|
output += 'href="' + outHref + '"';
|
||||||
|
}
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
output += ' title="' + title + '"';
|
output += ' title="' + title + '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outHref.lastIndexOf(Utils.getTeamURLFromAddressBar(), 0) === 0) {
|
output += '>' + outText + '</a>';
|
||||||
output += '>';
|
|
||||||
} else {
|
|
||||||
output += ' target="_blank">';
|
|
||||||
}
|
|
||||||
|
|
||||||
output += outText + '</a>';
|
|
||||||
|
|
||||||
return prefix + output + suffix;
|
return prefix + output + suffix;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import Autolinker from 'autolinker';
|
import Autolinker from 'autolinker';
|
||||||
|
import {browserHistory} from 'react-router';
|
||||||
import Constants from './constants.jsx';
|
import Constants from './constants.jsx';
|
||||||
import * as Emoticons from './emoticons.jsx';
|
import * as Emoticons from './emoticons.jsx';
|
||||||
import * as Markdown from './markdown.jsx';
|
import * as Markdown from './markdown.jsx';
|
||||||
@@ -398,10 +399,13 @@ function replaceNewlines(text) {
|
|||||||
export function handleClick(e) {
|
export function handleClick(e) {
|
||||||
const mentionAttribute = e.target.getAttributeNode('data-mention');
|
const mentionAttribute = e.target.getAttributeNode('data-mention');
|
||||||
const hashtagAttribute = e.target.getAttributeNode('data-hashtag');
|
const hashtagAttribute = e.target.getAttributeNode('data-hashtag');
|
||||||
|
const linkAttribute = e.target.getAttributeNode('data-link');
|
||||||
|
|
||||||
if (mentionAttribute) {
|
if (mentionAttribute) {
|
||||||
Utils.searchForTerm(mentionAttribute.value);
|
Utils.searchForTerm(mentionAttribute.value);
|
||||||
} else if (hashtagAttribute) {
|
} else if (hashtagAttribute) {
|
||||||
Utils.searchForTerm(hashtagAttribute.value);
|
Utils.searchForTerm(hashtagAttribute.value);
|
||||||
|
} else if (linkAttribute) {
|
||||||
|
browserHistory.push(linkAttribute.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user