From d293bc0b799a679cd27ed4ef6e818b0ca96998d9 Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Wed, 8 Jul 2015 11:34:34 -0700 Subject: Implemented basic text formatting package using a modfied version of the marked js library. Supports *bold*, _italics_, and `code` --- web/react/components/channel_header.jsx | 2 +- web/react/components/create_comment.jsx | 7 +- web/react/components/create_post.jsx | 7 +- web/react/components/post_body.jsx | 25 ++++-- web/react/components/post_list.jsx | 9 +- web/react/components/post_right.jsx | 29 +++++- web/react/components/search_results.jsx | 12 ++- web/react/components/sidebar.jsx | 6 ++ web/react/utils/utils.jsx | 153 ++++++++++++++++++++++++++------ 9 files changed, 208 insertions(+), 42 deletions(-) (limited to 'web/react') diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx index 90a776791..4d64e2b94 100644 --- a/web/react/components/channel_header.jsx +++ b/web/react/components/channel_header.jsx @@ -156,7 +156,7 @@ module.exports = React.createClass({ } var channel = this.state.channel; - var description = utils.textToJsx(channel.description, {singleline: true, noMentionHighlight: true}); + var description = utils.textToJsx(channel.description, {singleline: true, noMentionHighlight: true, noTextFormatting: true}); var popoverContent = React.renderToString(); var channelTitle = channel.display_name; var currentId = UserStore.getCurrentId(); diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx index 78e06c532..a0a018025 100644 --- a/web/react/components/create_comment.jsx +++ b/web/react/components/create_comment.jsx @@ -184,6 +184,7 @@ module.exports = React.createClass({ ); } + var allowTextFormatting = config.AllowTextFormatting; var postError = null; if (this.state.postError) { @@ -204,6 +205,10 @@ module.exports = React.createClass({ if (postError) { postFooterClassName += ' has-error'; } + var extraInfo = ; + if (this.state.messageText.split(' ').length > 1 && allowTextFormatting) { + extraInfo = _italics_ *bold* `code`; + } return (
@@ -224,7 +229,7 @@ module.exports = React.createClass({ onFileUpload={this.handleFileUploadComplete} onUploadError={this.handleUploadError} /> - + {extraInfo}
{postError} diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 9ca1d5388..3e1faba7d 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -224,6 +224,7 @@ module.exports = React.createClass({
); } + var allowTextFormatting = config.AllowTextFormatting; var postError = null; if (this.state.postError) { @@ -244,6 +245,10 @@ module.exports = React.createClass({ if (postError) { postFooterClassName += ' has-error'; } + var extraInfo = ; + if (this.state.messageText.split(' ').length > 1 && allowTextFormatting) { + extraInfo = _italics_ *bold* `code`; + } return ( @@ -268,7 +273,7 @@ module.exports = React.createClass({ {postError} {serverError} {preview} - + {extraInfo} diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index 860c96d84..bf039d79b 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -4,6 +4,7 @@ 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) { @@ -19,6 +20,7 @@ module.exports = React.createClass({ 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 reply = ""; @@ -50,11 +52,20 @@ module.exports = React.createClass({ } } - comment = ( -

- Commented on {name}{apostrophe} message: {message} -

- ); + if (allowTextFormatting) { + message = formatText(message, {sanitize: true, mangle: false, gfm: true, breaks: true, tables: false, smartypants: true, renderer: utils.customMarkedRenderer({disable: true})}); + comment = ( +

+ Commented on {name}{apostrophe} message: +

+ ); + } else { + comment = ( +

+ Commented on {name}{apostrophe} message: {message} +

+ ); + } postClass += " post-comment"; } @@ -67,7 +78,11 @@ module.exports = React.createClass({ return (
{ comment } + {allowTextFormatting ? +
{inner}
+ :

{inner}

+ } { filenames && filenames.length > 0 ? ); diff --git a/web/react/components/post_right.jsx b/web/react/components/post_right.jsx index ad8b54012..10a9400f5 100644 --- a/web/react/components/post_right.jsx +++ b/web/react/components/post_right.jsx @@ -56,6 +56,7 @@ 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; @@ -76,6 +77,11 @@ RootPost = React.createClass({ channelName = (channel.type === 'D') ? "Private Message" : channel.display_name; } + var messageHolder =

{message}

; + if (allowTextFormatting) { + messageHolder =
{message}
; + } + return (
{ channelName }
@@ -101,7 +107,7 @@ RootPost = React.createClass({
-

{message}

+ {messageHolder} { post.filenames && post.filenames.length > 0 ? {message}

; + if (allowTextFormatting) { + messageHolder =
{message}
; + } + return (
@@ -160,7 +172,7 @@ CommentPost = React.createClass({
-

{message}

+ {messageHolder} { post.filenames && post.filenames.length > 0 ?
- +
{ posts_array.map(function(cpost) { - return + return })}
diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx index 643ad112b..8f6bd861a 100644 --- a/web/react/components/search_results.jsx +++ b/web/react/components/search_results.jsx @@ -84,6 +84,8 @@ var SearchItem = React.createClass({ channelName = (channel.type === 'D') ? "Private Message" : channel.display_name; } + var searchItemKey = Date.now().toString(); + return (
{ channelName }
@@ -99,7 +101,7 @@ var SearchItem = React.createClass({ -
{message}
+
{message}
); @@ -131,6 +133,7 @@ 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); } } @@ -152,6 +155,11 @@ 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 (
{searchForm}
@@ -162,7 +170,7 @@ module.exports = React.createClass({ { noResults ?
No results
: results.order.map(function(id) { var post = results.posts[id]; - return + return }, this) } diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index fe73cbcf7..d6711f29c 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -11,6 +11,7 @@ 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; @@ -207,6 +208,11 @@ 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') { diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 2214b6239..d4654d7d5 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -9,6 +9,7 @@ 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})+$/; @@ -95,9 +96,8 @@ 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') { + if ("Notification" in window && Notification.permission !== 'denied') { Notification.requestPermission(function (permission) { if (Notification.permission !== permission) { Notification.permission = permission; @@ -385,11 +385,53 @@ 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, title, text) { + return href; + }; + customTextRenderer.image = function(href, title, text) { + return href; + }; + } else { + customTextRenderer.link = function(href, title, text) { + return href; + }; + customTextRenderer.image = function(href, title, text) { + return href; + }; + } + return customTextRenderer; +}; + var oldExplicitMentionRegex = /(?:)([\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) { + var useTextFormatting = config.AllowTextFormatting && (!options || !options.noTextFormatting); + + 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"); @@ -398,7 +440,7 @@ module.exports.textToJsx = function(text, options) { var searchTerm = "" if (options && options['searchTerm']) { - searchTerm = options['searchTerm'].toLowerCase() + searchTerm = options['searchTerm'].toLowerCase(); } var mentionClass = "mention-highlight"; @@ -407,6 +449,8 @@ module.exports.textToJsx = function(text, options) { } 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; @@ -420,16 +464,45 @@ module.exports.textToJsx = function(text, options) { var highlightSearchClass = ""; for (var z = 0; z < words.length; z++) { var word = words[z]; - var trimWord = word.replace(puncStartRegex, '').replace(puncEndRegex, '').trim(); + var trimWord; + if (useTextFormatting) { + trimWord = word.replace(endTagRegex, '').replace(startTagRegex, '').replace(puncStartRegex, '').replace(puncEndRegex, '').trim(); + } else { + 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); - if ((trimWord.toLowerCase().indexOf(searchTerm) > -1 || word.toLowerCase().indexOf(searchTerm) > -1) && searchTerm != "") { + var prefix; + var suffix; + var prefixSpan; + var suffixSpan; + if (useTextFormatting) { + prefix = (word.match(startTagRegex) ? word.match(startTagRegex) : "") + (word.replace(startTagRegex, '').match(puncStartRegex) ? word.replace(startTagRegex, '').match(puncStartRegex) : ""); + suffix = (word.match(endTagRegex) ? word.match(endTagRegex) : "") + (word.replace(endTagRegex, '').match(puncEndRegex) ? word.replace(endTagRegex, '').match(puncEndRegex) : ""); + prefixSpan = prefix ? () : null; + suffixSpan = suffix ? ( ) : ( ); + } else { + prefix = word.match(puncStartRegex); + suffix = word.match(puncEndRegex); + prefixSpan = prefix ? ({prefix}) : null; + suffixSpan = suffix ? ({suffix} ) : ( ); + } + if ((trimWord.toLowerCase().indexOf(searchTerm) > -1 || word.toLowerCase().indexOf(searchTerm) > -1) && searchTerm != "") { highlightSearchClass = " search-highlight"; } - if (explicitMention && + if (useTextFormatting && (codeFlag || word.indexOf('') !== -1)) { + codeString += word + ' '; + codeFlag = true; + + if (word.indexOf('') !== -1) { + inner.push(); + codeString = ''; + codeFlag = false; + } + } else if (explicitMention && (UserStore.getProfileByUsername(explicitMention[1]) || Constants.SPECIAL_MENTIONS.indexOf(explicitMention[1]) !== -1)) { @@ -437,60 +510,86 @@ module.exports.textToJsx = function(text, options) { // do both a non-case sensitive and case senstive check 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"; } - inner.push({prefix}@{name}{suffix} ); + if (useTextFormatting) { + prefixSpan ? inner.push(prefixSpan) : null; + inner.push({"@" + name}); + suffixSpan ? inner.push(suffixSpan) : null; + } + else + inner.push({prefix}@{name}{suffix} ); } else if (testUrlMatch(word).length) { var match = testUrlMatch(word)[0]; var link = match.link; - var prefix = word.substring(0,word.indexOf(match.text)); - var suffix = word.substring(word.indexOf(match.text)+match.text.length); - - inner.push({prefix}{match.text}{suffix} ); + prefix = word.substring(0,word.indexOf(match.text)); + suffix = word.substring(word.indexOf(match.text)+match.text.length); + prefixSpan = prefix ? () : null; + suffixSpan = suffix ? ( ) : ; + if (useTextFormatting) { + prefixSpan ? inner.push(prefixSpan) : null; + inner.push({match.text}); + suffixSpan ? inner.push(suffixSpan) : null; + } + else + inner.push({prefix}{match.text}{suffix} ); } else if (trimWord.match(hashRegex)) { - 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"; } - inner.push({prefix}{trimWord}{suffix} ); + if (useTextFormatting) { + prefixSpan ? inner.push(prefixSpan) : null; + inner.push({trimWord}); + suffixSpan ? inner.push(suffixSpan) : null; + } + else + inner.push({prefix}{trimWord}{suffix} ); } 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"; } - inner.push({prefix}{trimWord}{suffix} ); + if (useTextFormatting) { + prefixSpan ? inner.push(prefixSpan) : null; + inner.push({trimWord}); + suffixSpan ? inner.push(suffixSpan) : null; + } + else + inner.push({prefix}{trimWord}{suffix} ); } else { - inner.push({prefix}{module.exports.replaceHtmlEntities(trimWord)}{suffix} ); + if (useTextFormatting) { + prefixSpan ? inner.push(prefixSpan) : null; + inner.push({trimWord}); + suffixSpan ? inner.push(suffixSpan) : null; + } + else + inner.push({prefix}{module.exports.replaceHtmlEntities(trimWord)}{suffix} ); } } else if (word === "") { // if word is empty dont include a span } else { - inner.push({module.exports.replaceHtmlEntities(word)} ); + if (useTextFormatting) + inner.push(); + else + inner.push({module.exports.replaceHtmlEntities(word)} ); } highlightSearchClass = ""; } - if (i != lines.length-1) + if (!useTextFormatting && i != lines.length-1) inner.push(
); } return inner; -} +}; module.exports.getFileType = function(ext) { ext = ext.toLowerCase(); -- cgit v1.2.3-1-g7c22 From 23a331f933af834ed1a26806f087e61ca6ddd93a Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Mon, 10 Aug 2015 16:44:54 -0700 Subject: Cosmetic refactoring of textToJsx function --- web/react/utils/utils.jsx | 213 ++++++++++++++++++++++++++++------------------ 1 file changed, 131 insertions(+), 82 deletions(-) (limited to 'web/react') diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index d4654d7d5..bbe5003bc 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -403,49 +403,49 @@ module.exports.customMarkedRenderer = function(options) { customTextRenderer.codespan = function(code) { return code; }; - customTextRenderer.link = function(href, title, text) { + customTextRenderer.link = function(href) { return href; }; - customTextRenderer.image = function(href, title, text) { + customTextRenderer.image = function(href) { return href; }; } else { - customTextRenderer.link = function(href, title, text) { + customTextRenderer.link = function(href) { return href; }; - customTextRenderer.image = function(href, title, text) { + customTextRenderer.image = function(href) { return href; }; } return customTextRenderer; }; -var oldExplicitMentionRegex = /(?:)([\s\S]*?)(?:<\/mention>)/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 = []; @@ -457,11 +457,11 @@ module.exports.textToJsx = function(text, options) { 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; @@ -472,25 +472,46 @@ module.exports.textToJsx = function(text, options) { } 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; - var suffixSpan; + var prefix = ''; + var suffix = ''; + var prefixSpan = null; + var suffixSpan = ; if (useTextFormatting) { - prefix = (word.match(startTagRegex) ? word.match(startTagRegex) : "") + (word.replace(startTagRegex, '').match(puncStartRegex) ? word.replace(startTagRegex, '').match(puncStartRegex) : ""); - suffix = (word.match(endTagRegex) ? word.match(endTagRegex) : "") + (word.replace(endTagRegex, '').match(puncEndRegex) ? word.replace(endTagRegex, '').match(puncEndRegex) : ""); - prefixSpan = prefix ? () : null; - suffixSpan = suffix ? ( ) : ( ); + if (word.match(startTagRegex)) { + prefix += word.match(startTagRegex); + } + if (word.replace(startTagRegex, '').match(puncStartRegex)) { + prefix += word.replace(startTagRegex, '').match(puncStartRegex); + } + + if (word.match(endTagRegex)) { + suffix += word.match(endTagRegex); + } + if (word.replace(endTagRegex, '').match(puncEndRegex)) { + suffix += word.replace(endTagRegex, '').match(puncEndRegex); + } + + if (prefix) { + prefixSpan = ; + } + if (suffix) { + suffixSpan = ; + } } else { prefix = word.match(puncStartRegex); suffix = word.match(puncEndRegex); - prefixSpan = prefix ? ({prefix}) : null; - suffixSpan = suffix ? ({suffix} ) : ( ); + if (prefix) { + prefixSpan = {prefix}; + } + if (suffix) { + suffixSpan = {suffix} ; + } } - if ((trimWord.toLowerCase().indexOf(searchTerm) > -1 || word.toLowerCase().indexOf(searchTerm) > -1) && searchTerm != "") { - highlightSearchClass = " search-highlight"; + if ((trimWord.toLowerCase().indexOf(searchTerm) > -1 || word.toLowerCase().indexOf(searchTerm) > -1) && searchTerm !== '') { + highlightSearchClass = ' search-highlight'; } if (useTextFormatting && (codeFlag || word.indexOf('') !== -1)) { @@ -498,94 +519,122 @@ module.exports.textToJsx = function(text, options) { codeFlag = true; if (word.indexOf('') !== -1) { - inner.push(); + inner.push(); codeString = ''; codeFlag = false; } } else if (explicitMention && - (UserStore.getProfileByUsername(explicitMention[1]) || - Constants.SPECIAL_MENTIONS.indexOf(explicitMention[1]) !== -1)) - { + (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 - var mClass = implicitKeywords.indexOf('@'+name.toLowerCase()) !== -1 || implicitKeywords.indexOf('@'+name) !== -1 ? mentionClass : ""; + mClass = ''; + if (implicitKeywords.indexOf('@' + name.toLowerCase()) !== -1 || implicitKeywords.indexOf('@' + name) !== -1) { + mClass = mentionClass; + } if (searchTerm === name) { - highlightSearchClass = " search-highlight"; + highlightSearchClass = ' search-highlight'; } if (useTextFormatting) { - prefixSpan ? inner.push(prefixSpan) : null; - inner.push({"@" + name}); - suffixSpan ? inner.push(suffixSpan) : null; + if (prefixSpan) { + inner.push(prefixSpan); + } + inner.push({'@' + name}); + if (suffixSpan) { + inner.push(suffixSpan); + } + } else { + inner.push({prefix}@{name}{suffix} ); } - else - inner.push({prefix}@{name}{suffix} ); } 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); - prefixSpan = prefix ? () : null; - suffixSpan = suffix ? ( ) : ; + prefix = word.substring(0, word.indexOf(match.text)); + suffix = word.substring(word.indexOf(match.text) + match.text.length); + if (prefix) { + prefixSpan = ; + } + if (suffix) { + suffixSpan = ; + } else { + suffixSpan = ; + } if (useTextFormatting) { - prefixSpan ? inner.push(prefixSpan) : null; - inner.push({match.text}); - suffixSpan ? inner.push(suffixSpan) : null; + if (prefixSpan) { + inner.push(prefixSpan); + } + inner.push({match.text}); + if (suffixSpan) { + inner.push(suffixSpan); + } + } else { + inner.push({prefix}{match.text}{suffix} ); } - else - inner.push({prefix}{match.text}{suffix} ); } else if (trimWord.match(hashRegex)) { - var mClass = implicitKeywords.indexOf(trimWord) !== -1 || implicitKeywords.indexOf(trimWord.toLowerCase()) !== -1 ? mentionClass : ""; + mClass = ''; + if (implicitKeywords.indexOf(trimWord) !== -1 || implicitKeywords.indexOf(trimWord.toLowerCase()) !== -1) { + mClass = mentionClass; + } if (searchTerm === trimWord.substring(1).toLowerCase() || searchTerm === trimWord.toLowerCase()) { - highlightSearchClass = " search-highlight"; + highlightSearchClass = ' search-highlight'; } if (useTextFormatting) { - prefixSpan ? inner.push(prefixSpan) : null; - inner.push({trimWord}); - suffixSpan ? inner.push(suffixSpan) : null; + if (prefixSpan) { + inner.push(prefixSpan); + } + inner.push({trimWord}); + if (suffixSpan) { + inner.push(suffixSpan); + } + } else { + inner.push({prefix}{trimWord}{suffix} ); } - else - inner.push({prefix}{trimWord}{suffix} ); - } else if (implicitKeywords.indexOf(trimWord) !== -1 || implicitKeywords.indexOf(trimWord.toLowerCase()) !== -1) { if (trimWord.charAt(0) === '@') { if (searchTerm === trimWord.substring(1).toLowerCase()) { - highlightSearchClass = " search-highlight"; + highlightSearchClass = ' search-highlight'; } if (useTextFormatting) { - prefixSpan ? inner.push(prefixSpan) : null; - inner.push({trimWord}); - suffixSpan ? inner.push(suffixSpan) : null; + if (prefixSpan) { + inner.push(prefixSpan); + } + inner.push({trimWord}); + if (suffixSpan) { + inner.push(suffixSpan); + } + } else { + inner.push({prefix}{trimWord}{suffix} ); } - else - inner.push({prefix}{trimWord}{suffix} ); - } else { - if (useTextFormatting) { - prefixSpan ? inner.push(prefixSpan) : null; - inner.push({trimWord}); - suffixSpan ? inner.push(suffixSpan) : null; + } else if (useTextFormatting) { + if (prefixSpan) { + inner.push(prefixSpan); + } + inner.push({trimWord}); + if (suffixSpan) { + inner.push(suffixSpan); } - else - inner.push({prefix}{module.exports.replaceHtmlEntities(trimWord)}{suffix} ); + } else { + inner.push({prefix}{module.exports.replaceHtmlEntities(trimWord)}{suffix} ); + } + } else if (word !== '') { + if (useTextFormatting) { + inner.push(); + } else { + inner.push({module.exports.replaceHtmlEntities(word)} ); } - - } else if (word === "") { - // if word is empty dont include a span - } else { - if (useTextFormatting) - inner.push(); - else - inner.push({module.exports.replaceHtmlEntities(word)} ); } - highlightSearchClass = ""; + highlightSearchClass = ''; + } + if (!useTextFormatting && i !== lines.length - 1) { + inner.push(
); } - if (!useTextFormatting && i != lines.length-1) - inner.push(
); } return inner; -- cgit v1.2.3-1-g7c22 From e02883baf2fd2a0cfc21bd557bc0ecc69afd707c Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Mon, 10 Aug 2015 16:51:59 -0700 Subject: Cosmetic refactoring of post_body.jsx --- web/react/components/post_body.jsx | 69 +++++++++++++++++++------------------ web/react/components/post_list.jsx | 3 +- web/react/components/post_right.jsx | 6 ++-- web/react/utils/utils.jsx | 2 ++ 4 files changed, 44 insertions(+), 36 deletions(-) (limited to 'web/react') diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index bf039d79b..fab6833e6 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -9,11 +9,11 @@ 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; @@ -22,52 +22,51 @@ module.exports = React.createClass({ var inner = utils.textToJsx(this.state.message); var allowTextFormatting = config.AllowTextFormatting; - var comment = ""; - var reply = ""; - var postClass = ""; + var comment = ''; + 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 = {profile.username}; + name = {profile.username}; } - 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 = ( -

- Commented on {name}{apostrophe} message: +

+ Commented on {name}{apostrophe} message:

); } else { comment = ( -

- Commented on {name}{apostrophe} message: {message} +

+ Commented on {name}{apostrophe} message: {message}

); } - postClass += " post-comment"; + postClass += ' post-comment'; } var embed; @@ -75,22 +74,26 @@ module.exports = React.createClass({ embed = utils.getEmbed(this.state.links[0]); } + var innerHolder =

{inner}

; + if (allowTextFormatting) { + innerHolder =
{inner}
; + } + + var fileAttachmentHolder = ''; + if (filenames && filenames.length > 0) { + fileAttachmentHolder = (); + } + return ( -
- { comment } - {allowTextFormatting ? -
{inner}
- : -

{inner}

- } - { filenames && filenames.length > 0 ? - - : "" } - { embed } +
+ {comment} + {innerHolder} + {fileAttachmentHolder} + {embed}
); } diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx index 12875ee90..ad7f4a8bf 100644 --- a/web/react/components/post_list.jsx +++ b/web/react/components/post_list.jsx @@ -434,8 +434,9 @@ module.exports = React.createClass({ var isLastComment = utils.isComment(post) && (i === 0 || posts[order[i-1]].root_id != post.root_id); var postKey = post.id; - if (post.lastEditDate != undefined) + if (post.lastEditDate) { postKey += post.lastEditDate; + } var postCtl = ( ); + } else if (useTextFormatting && !codeFlag && i < lines.length - 2) { + inner.push(
); } } -- cgit v1.2.3-1-g7c22 From 41e74860d8abc8e33648471249b127dd3f60fb88 Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Wed, 12 Aug 2015 11:02:47 -0700 Subject: Cosmetic refactoring of the notifyMe function in utils.jsx and removed unnecessary files --- web/react/utils/utils.jsx | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'web/react') diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 2136accb4..2a4cbaa62 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -97,31 +97,31 @@ module.exports.getCookie = function(name) { } 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 ('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); - } - }); - } -} + 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'); -- cgit v1.2.3-1-g7c22