Revert "MM-375 Adds text formatting features using a modified version of the marked js library"
Этот коммит содержится в:
@@ -156,7 +156,7 @@ module.exports = React.createClass({
|
||||
}
|
||||
|
||||
var channel = this.state.channel;
|
||||
var description = utils.textToJsx(channel.description, {singleline: true, noMentionHighlight: true, noTextFormatting: true});
|
||||
var description = utils.textToJsx(channel.description, {singleline: true, noMentionHighlight: true});
|
||||
var popoverContent = React.renderToString(<MessageWrapper message={channel.description}/>);
|
||||
var channelTitle = channel.display_name;
|
||||
var currentId = UserStore.getCurrentId();
|
||||
|
||||
@@ -184,7 +184,6 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
var allowTextFormatting = config.AllowTextFormatting;
|
||||
|
||||
var postError = null;
|
||||
if (this.state.postError) {
|
||||
@@ -205,10 +204,6 @@ module.exports = React.createClass({
|
||||
if (postError) {
|
||||
postFooterClassName += ' has-error';
|
||||
}
|
||||
var extraInfo = <MsgTyping channelId={this.props.channelId} parentId={this.props.rootId} />;
|
||||
if (this.state.messageText.split(' ').length > 1 && allowTextFormatting) {
|
||||
extraInfo = <span className='msg-format-help'>_<em>italics</em>_ *<strong>bold</strong>* `<code className='code-info'>code</code>`</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
@@ -229,7 +224,7 @@ module.exports = React.createClass({
|
||||
onFileUpload={this.handleFileUploadComplete}
|
||||
onUploadError={this.handleUploadError} />
|
||||
</div>
|
||||
{extraInfo}
|
||||
<MsgTyping channelId={this.props.channelId} parentId={this.props.rootId} />
|
||||
<div className={postFooterClassName}>
|
||||
<input type='button' className='btn btn-primary comment-btn pull-right' value='Add Comment' onClick={this.handleSubmit} />
|
||||
{postError}
|
||||
|
||||
@@ -224,7 +224,6 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
var allowTextFormatting = config.AllowTextFormatting;
|
||||
|
||||
var postError = null;
|
||||
if (this.state.postError) {
|
||||
@@ -245,10 +244,6 @@ module.exports = React.createClass({
|
||||
if (postError) {
|
||||
postFooterClassName += ' has-error';
|
||||
}
|
||||
var extraInfo = <MsgTyping channelId={this.state.channel_id} parentId='' />;
|
||||
if (this.state.messageText.split(' ').length > 1 && allowTextFormatting) {
|
||||
extraInfo = <span className='msg-typing'>_<em>italics</em>_ *<strong>bold</strong>* `<code className='code-info'>code</code>`</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<form id='create_post' ref='topDiv' role='form' onSubmit={this.handleSubmit}>
|
||||
@@ -273,7 +268,7 @@ module.exports = React.createClass({
|
||||
{postError}
|
||||
{serverError}
|
||||
{preview}
|
||||
{extraInfo}
|
||||
<MsgTyping channelId={this.state.channelId} parentId=''/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -4,69 +4,59 @@
|
||||
var FileAttachmentList = require('./file_attachment_list.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var formatText = require('../../static/js/marked/lib/marked.js');
|
||||
|
||||
module.exports = React.createClass({
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
var linkData = utils.extractLinks(nextProps.post.message);
|
||||
this.setState({links: linkData.links, message: linkData.text});
|
||||
this.setState({ links: linkData["links"], message: linkData["text"] });
|
||||
},
|
||||
getInitialState: function() {
|
||||
var linkData = utils.extractLinks(this.props.post.message);
|
||||
return {links: linkData.links, message: linkData.text};
|
||||
return { links: linkData["links"], message: linkData["text"] };
|
||||
},
|
||||
render: function() {
|
||||
var post = this.props.post;
|
||||
var filenames = this.props.post.filenames;
|
||||
var parentPost = this.props.parentPost;
|
||||
var inner = utils.textToJsx(this.state.message);
|
||||
var allowTextFormatting = config.AllowTextFormatting;
|
||||
|
||||
var comment = '';
|
||||
var postClass = '';
|
||||
var comment = "";
|
||||
var reply = "";
|
||||
var postClass = "";
|
||||
|
||||
if (parentPost) {
|
||||
var profile = UserStore.getProfile(parentPost.user_id);
|
||||
var apostrophe = '';
|
||||
var name = '...';
|
||||
var apostrophe = "";
|
||||
var name = "...";
|
||||
if (profile != null) {
|
||||
if (profile.username.slice(-1) === 's') {
|
||||
apostrophe = "'";
|
||||
} else {
|
||||
apostrophe = "'s";
|
||||
}
|
||||
name = <a className='theme' onClick={utils.searchForTerm.bind(this, profile.username)}>{profile.username}</a>;
|
||||
name = <a className="theme" onClick={function(){ utils.searchForTerm(profile.username); }}>{profile.username}</a>;
|
||||
}
|
||||
|
||||
var message = '';
|
||||
if (parentPost.message) {
|
||||
message = utils.replaceHtmlEntities(parentPost.message);
|
||||
var message = ""
|
||||
if(parentPost.message) {
|
||||
message = utils.replaceHtmlEntities(parentPost.message)
|
||||
} else if (parentPost.filenames.length) {
|
||||
message = parentPost.filenames[0].split('/').pop();
|
||||
|
||||
if (parentPost.filenames.length === 2) {
|
||||
message += ' plus 1 other file';
|
||||
message += " plus 1 other file";
|
||||
} else if (parentPost.filenames.length > 2) {
|
||||
message += ' plus ' + (parentPost.filenames.length - 1) + ' other files';
|
||||
message += " plus " + (parentPost.filenames.length - 1) + " other files";
|
||||
}
|
||||
}
|
||||
|
||||
if (allowTextFormatting) {
|
||||
message = formatText(message, {sanitize: true, mangle: false, gfm: true, breaks: true, tables: false, smartypants: true, renderer: utils.customMarkedRenderer({disable: true})});
|
||||
comment = (
|
||||
<p className='post-link'>
|
||||
<span>Commented on {name}{apostrophe} message: <a className='theme' onClick={this.props.handleCommentClick} dangerouslySetInnerHTML={{__html: message}} /></span>
|
||||
</p>
|
||||
);
|
||||
} else {
|
||||
comment = (
|
||||
<p className='post-link'>
|
||||
<span>Commented on {name}{apostrophe} message: <a className='theme' onClick={this.props.handleCommentClick}>{message}</a></span>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
comment = (
|
||||
<p className="post-link">
|
||||
<span>Commented on {name}{apostrophe} message: <a className="theme" onClick={this.props.handleCommentClick}>{message}</a></span>
|
||||
</p>
|
||||
);
|
||||
|
||||
postClass += ' post-comment';
|
||||
postClass += " post-comment";
|
||||
}
|
||||
|
||||
var embed;
|
||||
@@ -74,26 +64,18 @@ module.exports = React.createClass({
|
||||
embed = utils.getEmbed(this.state.links[0]);
|
||||
}
|
||||
|
||||
var innerHolder = <p key={post.id + '_message'} className={postClass}><span>{inner}</span></p>;
|
||||
if (allowTextFormatting) {
|
||||
innerHolder = <div key={post.id + '_message'} className={postClass}><span>{inner}</span></div>;
|
||||
}
|
||||
|
||||
var fileAttachmentHolder = '';
|
||||
if (filenames && filenames.length > 0) {
|
||||
fileAttachmentHolder = (<FileAttachmentList
|
||||
filenames={filenames}
|
||||
modalId={'view_image_modal_' + post.id}
|
||||
channelId={post.channel_id}
|
||||
userId={post.user_id} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='post-body'>
|
||||
{comment}
|
||||
{innerHolder}
|
||||
{fileAttachmentHolder}
|
||||
{embed}
|
||||
<div className="post-body">
|
||||
{ comment }
|
||||
<p key={post.id+"_message"} className={postClass}><span>{inner}</span></p>
|
||||
{ filenames && filenames.length > 0 ?
|
||||
<FileAttachmentList
|
||||
filenames={filenames}
|
||||
modalId={"view_image_modal_" + post.id}
|
||||
channelId={post.channel_id}
|
||||
userId={post.user_id} />
|
||||
: "" }
|
||||
{ embed }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -197,10 +197,7 @@ module.exports = React.createClass({
|
||||
var post = post_list.posts[msg.props.post_id];
|
||||
post.message = msg.props.message;
|
||||
|
||||
post.lastEditDate = Date.now();
|
||||
|
||||
post_list.posts[post.id] = post;
|
||||
|
||||
this.setState({ post_list: post_list });
|
||||
|
||||
PostStore.storePosts(msg.channel_id, post_list);
|
||||
@@ -433,13 +430,8 @@ module.exports = React.createClass({
|
||||
// it is the last comment if it is last post in the channel or the next post has a different root post
|
||||
var isLastComment = utils.isComment(post) && (i === 0 || posts[order[i-1]].root_id != post.root_id);
|
||||
|
||||
var postKey = post.id;
|
||||
if (post.lastEditDate) {
|
||||
postKey += post.lastEditDate;
|
||||
}
|
||||
|
||||
var postCtl = (
|
||||
<Post ref={post.id} sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={postKey}
|
||||
<Post ref={post.id} sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={post.id}
|
||||
posts={posts} hideProfilePic={hideProfilePic} isLastComment={isLastComment}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -56,7 +56,6 @@ RhsHeaderPost = React.createClass({
|
||||
|
||||
RootPost = React.createClass({
|
||||
render: function() {
|
||||
var allowTextFormatting = config.AllowTextFormatting;
|
||||
var post = this.props.post;
|
||||
var message = utils.textToJsx(post.message);
|
||||
var isOwner = UserStore.getCurrentId() == post.user_id;
|
||||
@@ -77,11 +76,6 @@ RootPost = React.createClass({
|
||||
channelName = (channel.type === 'D') ? "Private Message" : channel.display_name;
|
||||
}
|
||||
|
||||
var messageHolder = <p>{message}</p>;
|
||||
if (allowTextFormatting) {
|
||||
messageHolder = <div>{message}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"post post--root " + currentUserCss}>
|
||||
<div className="post-right-channel__name">{ channelName }</div>
|
||||
@@ -107,7 +101,7 @@ RootPost = React.createClass({
|
||||
</li>
|
||||
</ul>
|
||||
<div className="post-body">
|
||||
{messageHolder}
|
||||
<p>{message}</p>
|
||||
{ post.filenames && post.filenames.length > 0 ?
|
||||
<FileAttachmentList
|
||||
filenames={post.filenames}
|
||||
@@ -125,7 +119,6 @@ RootPost = React.createClass({
|
||||
|
||||
CommentPost = React.createClass({
|
||||
render: function() {
|
||||
var allowTextFormatting = config.AllowTextFormatting;
|
||||
var post = this.props.post;
|
||||
|
||||
var commentClass = "post";
|
||||
@@ -145,11 +138,6 @@ CommentPost = React.createClass({
|
||||
var message = utils.textToJsx(post.message);
|
||||
var timestamp = UserStore.getCurrentUser().update_at;
|
||||
|
||||
var messageHolder = <p>{message}</p>;
|
||||
if (allowTextFormatting) {
|
||||
messageHolder = <div>{message}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={commentClass + " " + currentUserCss}>
|
||||
<div className="post-profile-img__container">
|
||||
@@ -172,7 +160,7 @@ CommentPost = React.createClass({
|
||||
</li>
|
||||
</ul>
|
||||
<div className="post-body">
|
||||
{messageHolder}
|
||||
<p>{message}</p>
|
||||
{ post.filenames && post.filenames.length > 0 ?
|
||||
<FileAttachmentList
|
||||
filenames={post.filenames}
|
||||
@@ -285,22 +273,11 @@ module.exports = React.createClass({
|
||||
root_post = post_list.posts[selected_post.root_id];
|
||||
}
|
||||
|
||||
var rootPostKey = root_post.id
|
||||
if (root_post.lastEditDate) {
|
||||
rootPostKey += root_post.lastEditDate;
|
||||
}
|
||||
|
||||
var posts_array = [];
|
||||
|
||||
for (var postId in post_list.posts) {
|
||||
var cpost = post_list.posts[postId];
|
||||
if (cpost.root_id == root_post.id) {
|
||||
var cpostKey = cpost.id
|
||||
if (cpost.lastEditDate) {
|
||||
cpostKey += cpost.lastEditDate;
|
||||
}
|
||||
|
||||
cpost.cpostKey = cpostKey;
|
||||
posts_array.push(cpost);
|
||||
}
|
||||
}
|
||||
@@ -323,10 +300,10 @@ module.exports = React.createClass({
|
||||
<div className="sidebar-right__body">
|
||||
<RhsHeaderPost fromSearch={this.props.fromSearch} isMentionSearch={this.props.isMentionSearch} />
|
||||
<div className="post-right__scroll">
|
||||
<RootPost key={rootPostKey} post={root_post} commentCount={posts_array.length}/>
|
||||
<RootPost post={root_post} commentCount={posts_array.length}/>
|
||||
<div className="post-right-comments-container">
|
||||
{ posts_array.map(function(cpost) {
|
||||
return <CommentPost ref={cpost.id} key={cpost.cpostKey} post={cpost} selected={ (cpost.id == selected_post.id) } />
|
||||
return <CommentPost ref={cpost.id} key={cpost.id} post={cpost} selected={ (cpost.id == selected_post.id) } />
|
||||
})}
|
||||
</div>
|
||||
<div className="post-create__container">
|
||||
|
||||
@@ -84,8 +84,6 @@ var SearchItem = React.createClass({
|
||||
channelName = (channel.type === 'D') ? "Private Message" : channel.display_name;
|
||||
}
|
||||
|
||||
var searchItemKey = Date.now().toString();
|
||||
|
||||
return (
|
||||
<div className="search-item-container post" onClick={this.handleClick}>
|
||||
<div className="search-channel__name">{ channelName }</div>
|
||||
@@ -101,7 +99,7 @@ var SearchItem = React.createClass({
|
||||
</time>
|
||||
</li>
|
||||
</ul>
|
||||
<div key={this.props.key + searchItemKey} className="search-item-snippet"><span>{message}</span></div>
|
||||
<div className="search-item-snippet"><span>{message}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -133,7 +131,6 @@ module.exports = React.createClass({
|
||||
if (this.isMounted()) {
|
||||
var newState = getStateFromStores();
|
||||
if (!utils.areStatesEqual(newState, this.state)) {
|
||||
newState.last_edit_time = Date.now();
|
||||
this.setState(newState);
|
||||
}
|
||||
}
|
||||
@@ -155,11 +152,6 @@ module.exports = React.createClass({
|
||||
var noResults = (!results || !results.order || !results.order.length);
|
||||
var searchTerm = PostStore.getSearchTerm();
|
||||
|
||||
var searchItemKey = "";
|
||||
if (this.state.last_edit_time) {
|
||||
searchItemKey += this.state.last_edit_time.toString();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="sidebar--right__content">
|
||||
<div className="search-bar__container sidebar--right__search-header">{searchForm}</div>
|
||||
@@ -170,7 +162,7 @@ module.exports = React.createClass({
|
||||
{ noResults ? <div className="sidebar--right__subheader">No results</div>
|
||||
: results.order.map(function(id) {
|
||||
var post = results.posts[id];
|
||||
return <SearchItem key={searchItemKey + post.id} post={post} term={searchTerm} isMentionSearch={this.props.isMentionSearch} />
|
||||
return <SearchItem key={post.id} post={post} term={searchTerm} isMentionSearch={this.props.isMentionSearch} />
|
||||
}, this)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ var BrowserStore = require('../stores/browser_store.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var SidebarHeader = require('./sidebar_header.jsx');
|
||||
var SearchBox = require('./search_bar.jsx');
|
||||
var formatText = require('../../static/js/marked/lib/marked.js');
|
||||
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
@@ -210,11 +209,6 @@ module.exports = React.createClass({
|
||||
utils.notifyMe(title, username + ' did something new', channel);
|
||||
}
|
||||
} else {
|
||||
var allowTextFormatting = config.AllowTextFormatting;
|
||||
if (allowTextFormatting) {
|
||||
notifyText = formatText(notifyText, {sanitize: false, mangle: false, gfm: true, breaks: true, tables: false, smartypants: true, renderer: utils.customMarkedRenderer({disable: true})});
|
||||
}
|
||||
notifyText = utils.replaceHtmlEntities(notifyText);
|
||||
utils.notifyMe(title, username + ' wrote: ' + notifyText, channel);
|
||||
}
|
||||
if (!user.notify_props || user.notify_props.desktop_sound === 'true') {
|
||||
|
||||
@@ -9,7 +9,6 @@ var ActionTypes = Constants.ActionTypes;
|
||||
var AsyncClient = require('./async_client.jsx');
|
||||
var client = require('./client.jsx');
|
||||
var Autolinker = require('autolinker');
|
||||
var formatText = require('../../static/js/marked/lib/marked.js');
|
||||
|
||||
module.exports.isEmail = function(email) {
|
||||
var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
|
||||
@@ -96,32 +95,33 @@ module.exports.getCookie = function(name) {
|
||||
if (parts.length == 2) return parts.pop().split(";").shift();
|
||||
}
|
||||
|
||||
module.exports.notifyMe = function(title, body, channel) {
|
||||
if ('Notification' in window && Notification.permission !== 'denied') {
|
||||
Notification.requestPermission(function(permission) {
|
||||
if (Notification.permission !== permission) {
|
||||
Notification.permission = permission;
|
||||
}
|
||||
|
||||
if (permission === 'granted') {
|
||||
var notification = new Notification(title,
|
||||
{body: body, tag: body, icon: '/static/images/icon50x50.gif'}
|
||||
);
|
||||
notification.onclick = function() {
|
||||
window.focus();
|
||||
if (channel) {
|
||||
module.exports.switchChannel(channel);
|
||||
} else {
|
||||
window.location.href = '/';
|
||||
}
|
||||
};
|
||||
setTimeout(function() {
|
||||
notification.close();
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
module.exports.notifyMe = function(title, body, channel) {
|
||||
if ("Notification" in window && Notification.permission !== 'denied') {
|
||||
Notification.requestPermission(function (permission) {
|
||||
if (Notification.permission !== permission) {
|
||||
Notification.permission = permission;
|
||||
}
|
||||
|
||||
if (permission === "granted") {
|
||||
var notification = new Notification(title,
|
||||
{ body: body, tag: body, icon: '/static/images/icon50x50.gif' }
|
||||
);
|
||||
notification.onclick = function() {
|
||||
window.focus();
|
||||
if (channel) {
|
||||
module.exports.switchChannel(channel);
|
||||
} else {
|
||||
window.location.href = "/";
|
||||
}
|
||||
};
|
||||
setTimeout(function(){
|
||||
notification.close();
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.ding = function() {
|
||||
var audio = new Audio('/static/images/ding.mp3');
|
||||
@@ -385,262 +385,112 @@ module.exports.searchForTerm = function(term) {
|
||||
});
|
||||
}
|
||||
|
||||
/* Options:
|
||||
- disable: Parses out *'s and other format specifiers in the text, but doesn't convert to html
|
||||
*/
|
||||
module.exports.customMarkedRenderer = function(options) {
|
||||
var customTextRenderer = new formatText.Renderer();
|
||||
if (options && options.disable) {
|
||||
customTextRenderer.paragraph = function(text) {
|
||||
return text + ' ';
|
||||
};
|
||||
customTextRenderer.strong = function(text) {
|
||||
return text;
|
||||
};
|
||||
customTextRenderer.em = function(text) {
|
||||
return text;
|
||||
};
|
||||
customTextRenderer.codespan = function(code) {
|
||||
return code;
|
||||
};
|
||||
customTextRenderer.link = function(href) {
|
||||
return href;
|
||||
};
|
||||
customTextRenderer.image = function(href) {
|
||||
return href;
|
||||
};
|
||||
} else {
|
||||
customTextRenderer.link = function(href) {
|
||||
return href;
|
||||
};
|
||||
customTextRenderer.image = function(href) {
|
||||
return href;
|
||||
};
|
||||
}
|
||||
return customTextRenderer;
|
||||
};
|
||||
var oldExplicitMentionRegex = /(?:<mention>)([\s\S]*?)(?:<\/mention>)/g;
|
||||
var puncStartRegex = /^((?![@#])\W)+/g;
|
||||
var puncEndRegex = /(\W)+$/g;
|
||||
|
||||
var puncStartRegex = /^((?![@#])[^A-Za-z0-9_<>])+/g;
|
||||
var puncEndRegex = /([^A-Za-z0-9_<>])+$/g;
|
||||
var startTagRegex = /(<\s*\w.*?>)+/g;
|
||||
var endTagRegex = /(<\s*\/\s*\w\s*.*?>|<\s*br\s*>)+/g;
|
||||
module.exports.textToJsx = function(text, options) {
|
||||
|
||||
module.exports.textToJsx = function(textToChange, options) {
|
||||
var useTextFormatting = config.AllowTextFormatting && (!options || !options.noTextFormatting);
|
||||
var text = textToChange;
|
||||
|
||||
if (useTextFormatting) {
|
||||
text = formatText(text, {sanitize: true, mangle: false, gfm: true, breaks: true, tables: false, smartypants: true, renderer: module.exports.customMarkedRenderer()});
|
||||
if (options && options['singleline']) {
|
||||
var repRegex = new RegExp("\n", "g");
|
||||
text = text.replace(repRegex, " ");
|
||||
}
|
||||
|
||||
if (options && options.singleline) {
|
||||
var repRegex = new RegExp('\n', 'g');
|
||||
text = text.replace(repRegex, ' ');
|
||||
var searchTerm = ""
|
||||
if (options && options['searchTerm']) {
|
||||
searchTerm = options['searchTerm'].toLowerCase()
|
||||
}
|
||||
|
||||
var searchTerm = '';
|
||||
if (options && options.searchTerm) {
|
||||
searchTerm = options.searchTerm.toLowerCase();
|
||||
}
|
||||
|
||||
var mentionClass = 'mention-highlight';
|
||||
if (options && options.noMentionHighlight) {
|
||||
mentionClass = '';
|
||||
var mentionClass = "mention-highlight";
|
||||
if (options && options['noMentionHighlight']) {
|
||||
mentionClass = "";
|
||||
}
|
||||
|
||||
var inner = [];
|
||||
var codeFlag = false;
|
||||
var codeString = '';
|
||||
|
||||
// Function specific regex
|
||||
var hashRegex = /^href="#[^"]+"|(#[A-Za-z]+[A-Za-z0-9_\-]*[A-Za-z0-9])$/g;
|
||||
|
||||
var implicitKeywords = UserStore.getCurrentMentionKeys();
|
||||
|
||||
var lines = text.split('\n');
|
||||
var lines = text.split("\n");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
var words = line.split(' ');
|
||||
var highlightSearchClass = '';
|
||||
var words = line.split(" ");
|
||||
var highlightSearchClass = "";
|
||||
for (var z = 0; z < words.length; z++) {
|
||||
var word = words[z];
|
||||
var trimWord;
|
||||
if (useTextFormatting) {
|
||||
trimWord = word.replace(endTagRegex, '').replace(startTagRegex, '').replace(puncStartRegex, '').replace(puncEndRegex, '').trim();
|
||||
} else {
|
||||
trimWord = word.replace(puncStartRegex, '').replace(puncEndRegex, '').trim();
|
||||
}
|
||||
var trimWord = word.replace(puncStartRegex, '').replace(puncEndRegex, '').trim();
|
||||
var mentionRegex = /^(?:@)([a-z0-9_]+)$/gi; // looks loop invariant but a weird JS bug needs it to be redefined here
|
||||
var explicitMention = mentionRegex.exec(trimWord);
|
||||
var mClass;
|
||||
|
||||
var prefix = '';
|
||||
var suffix = '';
|
||||
var prefixSpan = null;
|
||||
var suffixSpan = <span key={word + i + z + 'suf_span'}> </span>;
|
||||
if (useTextFormatting) {
|
||||
if (word.match(startTagRegex)) {
|
||||
prefix += word.match(startTagRegex);
|
||||
}
|
||||
if (word.replace(startTagRegex, '').match(puncStartRegex)) {
|
||||
prefix += word.replace(startTagRegex, '').match(puncStartRegex);
|
||||
}
|
||||
if ((trimWord.toLowerCase().indexOf(searchTerm) > -1 || word.toLowerCase().indexOf(searchTerm) > -1) && searchTerm != "") {
|
||||
|
||||
if (word.match(endTagRegex)) {
|
||||
suffix += word.match(endTagRegex);
|
||||
}
|
||||
if (word.replace(endTagRegex, '').match(puncEndRegex)) {
|
||||
suffix += word.replace(endTagRegex, '').match(puncEndRegex);
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
prefixSpan = <span key={word + i + z + 'pre_span'}><span dangerouslySetInnerHTML={{__html: prefix}} /></span>;
|
||||
}
|
||||
if (suffix) {
|
||||
suffixSpan = <span key={word + i + z + 'suf_span'}><span dangerouslySetInnerHTML={{__html: suffix}} /> </span>;
|
||||
}
|
||||
} else {
|
||||
prefix = word.match(puncStartRegex);
|
||||
suffix = word.match(puncEndRegex);
|
||||
if (prefix) {
|
||||
prefixSpan = <span key={word + i + z + 'pre_span'}>{prefix}</span>;
|
||||
}
|
||||
if (suffix) {
|
||||
suffixSpan = <span key={word + i + z + 'suf_span'}>{suffix} </span>;
|
||||
}
|
||||
highlightSearchClass = " search-highlight";
|
||||
}
|
||||
|
||||
if ((trimWord.toLowerCase().indexOf(searchTerm) > -1 || word.toLowerCase().indexOf(searchTerm) > -1) && searchTerm !== '') {
|
||||
highlightSearchClass = ' search-highlight';
|
||||
}
|
||||
|
||||
if (useTextFormatting && (codeFlag || word.indexOf('<code>') !== -1)) {
|
||||
codeString += word + ' ';
|
||||
codeFlag = true;
|
||||
|
||||
if (word.indexOf('</code>') !== -1) {
|
||||
inner.push(<span key={word + i + z + '_span'} className={highlightSearchClass} dangerouslySetInnerHTML={{__html: codeString}} />);
|
||||
codeString = '';
|
||||
codeFlag = false;
|
||||
}
|
||||
} else if (explicitMention &&
|
||||
(UserStore.getProfileByUsername(explicitMention[1]) ||
|
||||
Constants.SPECIAL_MENTIONS.indexOf(explicitMention[1]) !== -1)) {
|
||||
if (explicitMention &&
|
||||
(UserStore.getProfileByUsername(explicitMention[1]) ||
|
||||
Constants.SPECIAL_MENTIONS.indexOf(explicitMention[1]) !== -1))
|
||||
{
|
||||
var name = explicitMention[1];
|
||||
|
||||
// do both a non-case sensitive and case senstive check
|
||||
mClass = '';
|
||||
if (implicitKeywords.indexOf('@' + name.toLowerCase()) !== -1 || implicitKeywords.indexOf('@' + name) !== -1) {
|
||||
mClass = mentionClass;
|
||||
}
|
||||
var mClass = implicitKeywords.indexOf('@'+name.toLowerCase()) !== -1 || implicitKeywords.indexOf('@'+name) !== -1 ? mentionClass : "";
|
||||
|
||||
var suffix = word.match(puncEndRegex);
|
||||
var prefix = word.match(puncStartRegex);
|
||||
|
||||
if (searchTerm === name) {
|
||||
highlightSearchClass = ' search-highlight';
|
||||
highlightSearchClass = " search-highlight";
|
||||
}
|
||||
|
||||
if (useTextFormatting) {
|
||||
if (prefixSpan) {
|
||||
inner.push(prefixSpan);
|
||||
}
|
||||
inner.push(<span key={word + i + z + 'word_span'}><a className={mClass + highlightSearchClass + ' mention-link'} key={name + i + z + '_link'} href='#' onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(name)}>{'@' + name}</a></span>);
|
||||
if (suffixSpan) {
|
||||
inner.push(suffixSpan);
|
||||
}
|
||||
} else {
|
||||
inner.push(<span key={name + i + z + '_span'}>{prefix}<a className={mClass + highlightSearchClass + ' mention-link'} key={name + i + z + '_link'} href='#' onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(name)}>@{name}</a>{suffix} </span>);
|
||||
}
|
||||
inner.push(<span key={name+i+z+"_span"}>{prefix}<a className={mClass + highlightSearchClass + " mention-link"} key={name+i+z+"_link"} href="#" onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(name)}>@{name}</a>{suffix} </span>);
|
||||
} else if (testUrlMatch(word).length) {
|
||||
var match = testUrlMatch(word)[0];
|
||||
var link = match.link;
|
||||
|
||||
prefix = word.substring(0, word.indexOf(match.text));
|
||||
suffix = word.substring(word.indexOf(match.text) + match.text.length);
|
||||
if (prefix) {
|
||||
prefixSpan = <span key={word + i + z + 'pre_span'}><span dangerouslySetInnerHTML={{__html: prefix}} /></span>;
|
||||
}
|
||||
if (suffix) {
|
||||
suffixSpan = <span key={word + i + z + 'suf_span'}><span dangerouslySetInnerHTML={{__html: suffix}} /> </span>;
|
||||
} else {
|
||||
suffixSpan = <span key={word + i + z + 'suf_span'}> </span>;
|
||||
}
|
||||
var prefix = word.substring(0,word.indexOf(match.text));
|
||||
var suffix = word.substring(word.indexOf(match.text)+match.text.length);
|
||||
|
||||
inner.push(<span key={word+i+z+"_span"}>{prefix}<a key={word+i+z+"_link"} className={"theme" + highlightSearchClass} target="_blank" href={link}>{match.text}</a>{suffix} </span>);
|
||||
|
||||
if (useTextFormatting) {
|
||||
if (prefixSpan) {
|
||||
inner.push(prefixSpan);
|
||||
}
|
||||
inner.push(<span key={word + i + z + '_span'}><a key={name + i + z + '_link'} className={'theme' + highlightSearchClass} target='_blank' href={link}>{match.text}</a></span>);
|
||||
if (suffixSpan) {
|
||||
inner.push(suffixSpan);
|
||||
}
|
||||
} else {
|
||||
inner.push(<span key={word + i + z + '_span'}>{prefix}<a key={word + i + z + '_link'} className={'theme' + highlightSearchClass} target='_blank' href={link}>{match.text}</a>{suffix} </span>);
|
||||
}
|
||||
} else if (trimWord.match(hashRegex)) {
|
||||
mClass = '';
|
||||
if (implicitKeywords.indexOf(trimWord) !== -1 || implicitKeywords.indexOf(trimWord.toLowerCase()) !== -1) {
|
||||
mClass = mentionClass;
|
||||
}
|
||||
var suffix = word.match(puncEndRegex);
|
||||
var prefix = word.match(puncStartRegex);
|
||||
var mClass = implicitKeywords.indexOf(trimWord) !== -1 || implicitKeywords.indexOf(trimWord.toLowerCase()) !== -1 ? mentionClass : "";
|
||||
|
||||
if (searchTerm === trimWord.substring(1).toLowerCase() || searchTerm === trimWord.toLowerCase()) {
|
||||
highlightSearchClass = ' search-highlight';
|
||||
highlightSearchClass = " search-highlight";
|
||||
}
|
||||
|
||||
if (useTextFormatting) {
|
||||
if (prefixSpan) {
|
||||
inner.push(prefixSpan);
|
||||
}
|
||||
inner.push(<span key={word + i + z + '_span'}><a key={word + i + z + '_hash'} className={'theme ' + mClass + highlightSearchClass} href='#' onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(trimWord)}>{trimWord}</a></span>);
|
||||
if (suffixSpan) {
|
||||
inner.push(suffixSpan);
|
||||
}
|
||||
} else {
|
||||
inner.push(<span key={word + i + z + '_span'}>{prefix}<a key={word + i + z + '_hash'} className={'theme ' + mClass + highlightSearchClass} href='#' onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(trimWord)}>{trimWord}</a>{suffix} </span>);
|
||||
}
|
||||
inner.push(<span key={word+i+z+"_span"}>{prefix}<a key={word+i+z+"_hash"} className={"theme " + mClass + highlightSearchClass} href="#" onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(trimWord)}>{trimWord}</a>{suffix} </span>);
|
||||
|
||||
} else if (implicitKeywords.indexOf(trimWord) !== -1 || implicitKeywords.indexOf(trimWord.toLowerCase()) !== -1) {
|
||||
var suffix = word.match(puncEndRegex);
|
||||
var prefix = word.match(puncStartRegex);
|
||||
|
||||
if (trimWord.charAt(0) === '@') {
|
||||
if (searchTerm === trimWord.substring(1).toLowerCase()) {
|
||||
highlightSearchClass = ' search-highlight';
|
||||
}
|
||||
if (useTextFormatting) {
|
||||
if (prefixSpan) {
|
||||
inner.push(prefixSpan);
|
||||
}
|
||||
inner.push(<span key={word + i + z + '_span'}><a className={mentionClass + highlightSearchClass} key={name + i + z + '_link'} href='#'>{trimWord}</a></span>);
|
||||
if (suffixSpan) {
|
||||
inner.push(suffixSpan);
|
||||
}
|
||||
} else {
|
||||
inner.push(<span key={word + i + z + '_span'}>{prefix}<a className={mentionClass + highlightSearchClass} key={name + i + z + '_link'} href='#'>{trimWord}</a>{suffix} </span>);
|
||||
}
|
||||
} else if (useTextFormatting) {
|
||||
if (prefixSpan) {
|
||||
inner.push(prefixSpan);
|
||||
}
|
||||
inner.push(<span key={word + i + z + '_span'}><span className={mentionClass + highlightSearchClass}>{trimWord}</span></span>);
|
||||
if (suffixSpan) {
|
||||
inner.push(suffixSpan);
|
||||
highlightSearchClass = " search-highlight";
|
||||
}
|
||||
inner.push(<span key={word+i+z+"_span"} key={name+i+z+"_span"}>{prefix}<a className={mentionClass + highlightSearchClass} key={name+i+z+"_link"} href="#">{trimWord}</a>{suffix} </span>);
|
||||
} else {
|
||||
inner.push(<span key={word + i + z + '_span'}>{prefix}<span className={mentionClass + highlightSearchClass}>{module.exports.replaceHtmlEntities(trimWord)}</span>{suffix} </span>);
|
||||
}
|
||||
} else if (word !== '') {
|
||||
if (useTextFormatting) {
|
||||
inner.push(<span key={word + i + z + '_span'} className={highlightSearchClass} dangerouslySetInnerHTML={{__html: word + ' '}} />);
|
||||
} else {
|
||||
inner.push(<span key={word + i + z + '_span'}><span className={highlightSearchClass}>{module.exports.replaceHtmlEntities(word)}</span> </span>);
|
||||
inner.push(<span key={word+i+z+"_span"}>{prefix}<span className={mentionClass + highlightSearchClass}>{module.exports.replaceHtmlEntities(trimWord)}</span>{suffix} </span>);
|
||||
}
|
||||
|
||||
} else if (word === "") {
|
||||
// if word is empty dont include a span
|
||||
} else {
|
||||
inner.push(<span key={word+i+z+"_span"}><span className={highlightSearchClass}>{module.exports.replaceHtmlEntities(word)}</span> </span>);
|
||||
}
|
||||
highlightSearchClass = '';
|
||||
}
|
||||
if (!useTextFormatting && i !== lines.length - 1) {
|
||||
inner.push(<br key={'br_' + i}/>);
|
||||
} else if (useTextFormatting && !codeFlag && i < lines.length - 2) {
|
||||
inner.push(<br key={'br_' + i}/>);
|
||||
highlightSearchClass = "";
|
||||
}
|
||||
if (i != lines.length-1)
|
||||
inner.push(<br key={"br_"+i+z}/>);
|
||||
}
|
||||
|
||||
return inner;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.getFileType = function(ext) {
|
||||
ext = ext.toLowerCase();
|
||||
|
||||
Ссылка в новой задаче
Block a user