Skip to content

Commit 0b0fd9f

Browse files
Merge pull request #2 from aayush-kosh/mentions
mentions feature
2 parents 441a8f0 + 13dcab0 commit 0b0fd9f

File tree

7 files changed

+136
-52
lines changed

7 files changed

+136
-52
lines changed

dist/index.js

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,9 @@ function () {
714714
}];
715715
this.patterns.forEach(function (pattern) {
716716
var newParts = [];
717+
var tmp = pattern.nonExhaustiveModeMaxMatchCount || 0;
718+
var numberOfMatchesPermitted = Math.min(Math.max(Number.isInteger(tmp) ? tmp : 0, 0) || Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);
719+
var currentMatches = 0;
717720
parsedTexts.forEach(function (parsedText) {
718721
// Only allow for now one parsing
719722
if (parsedText._matched) {
@@ -723,20 +726,31 @@ function () {
723726

724727
var parts = [];
725728
var textLeft = parsedText.children;
729+
var indexOfMatchedString = 0;
730+
/** @type {RegExpExecArray} */
726731

727-
while (textLeft) {
728-
var matches = pattern.pattern.exec(textLeft);
732+
var matches; // Global RegExps are stateful, this makes it start at 0 if reused
733+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec
729734

730-
if (!matches) {
735+
pattern.pattern.lastIndex = 0;
736+
737+
while (textLeft && (matches = pattern.pattern.exec(textLeft))) {
738+
var previousText = textLeft.substr(0, matches.index);
739+
indexOfMatchedString = matches.index;
740+
741+
if (++currentMatches > numberOfMatchesPermitted) {
742+
// Abort if we've exhausted our number of matches
731743
break;
732744
}
733745

734-
var previousText = textLeft.substr(0, matches.index);
735746
parts.push({
736747
children: previousText
737748
});
738-
parts.push(_this.getMatchedPart(pattern, matches[0], matches));
749+
parts.push(_this.getMatchedPart(pattern, matches[0], matches, indexOfMatchedString));
739750
textLeft = textLeft.substr(matches.index + matches[0].length);
751+
indexOfMatchedString += matches[0].length - 1; // Global RegExps are stateful, this makes it operate on the "remainder" of the string
752+
753+
pattern.pattern.lastIndex = 0;
740754
}
741755

742756
parts.push({
@@ -797,6 +811,7 @@ function () {
797811
}();
798812

799813
var PATTERNS = {
814+
mention: /((.)\[([^[]*)]\(([^(^)]*)\))/gi,
800815
url: /(https?:\/\/|www\.)[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/i,
801816
phone: /[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}/,
802817
email: /\S+@\S+\.\S+/
@@ -896,6 +911,28 @@ function (_React$Component) {
896911
_classCallCheck(this, MessageText);
897912

898913
_this = _possibleConstructorReturn(this, _getPrototypeOf(MessageText).call(this, props));
914+
915+
_this.renderText = function (matchingString, matches) {
916+
var _this$props = _this.props,
917+
members = _this$props.members,
918+
profile = _this$props.profile;
919+
var name = matches[4];
920+
921+
if (profile && profile.username == name) {
922+
name = profile.name;
923+
} else {
924+
var user = members.find(function (user) {
925+
return user.id == matches[4];
926+
});
927+
928+
if (user) {
929+
name = user.display;
930+
}
931+
}
932+
933+
return "".concat(matches[2]).concat(name);
934+
};
935+
899936
_this.onUrlPress = _this.onUrlPress.bind(_assertThisInitialized(_assertThisInitialized(_this)));
900937
_this.onPhonePress = _this.onPhonePress.bind(_assertThisInitialized(_assertThisInitialized(_this)));
901938
_this.onEmailPress = _this.onEmailPress.bind(_assertThisInitialized(_assertThisInitialized(_this)));
@@ -928,20 +965,19 @@ function (_React$Component) {
928965
}, {
929966
key: "onPhonePress",
930967
value: function onPhonePress(phone) {
931-
var options = ['Call', 'Text', 'Cancel'];
932-
var cancelButtonIndex = options.length - 1;
933-
this.context.actionSheet().showActionSheetWithOptions({
934-
options: options,
935-
cancelButtonIndex: cancelButtonIndex
936-
}, function (buttonIndex) {// switch (buttonIndex) {
937-
// case 0:
938-
// Communications.phonecall(phone, true);
939-
// break;
940-
// case 1:
941-
// Communications.text(phone);
942-
// break;
943-
// }
944-
});
968+
// options,
969+
// cancelButtonIndex,
970+
// },
971+
// (buttonIndex) => {
972+
// // switch (buttonIndex) {
973+
// // case 0:
974+
// // Communications.phonecall(phone, true);
975+
// // break;
976+
// // case 1:
977+
// // Communications.text(phone);
978+
// // break;
979+
// // }
980+
// });
945981
}
946982
}, {
947983
key: "onEmailPress",
@@ -956,13 +992,18 @@ function (_React$Component) {
956992
}, React__default.createElement(ParsedText, {
957993
style: [styles$4[this.props.position].text, this.props.textStyle[this.props.position], this.props.customTextStyle],
958994
parse: _toConsumableArray(this.props.parsePatterns(linkStyle)).concat([{
995+
type: 'mention',
996+
style: linkStyle,
997+
onPress: null,
998+
renderText: this.renderText
999+
}, {
9591000
type: 'url',
9601001
style: linkStyle,
9611002
onPress: this.onUrlPress
9621003
}, {
9631004
type: 'phone',
9641005
style: linkStyle,
965-
onPress: null
1006+
onPress: this.onPhonePress
9661007
}, {
9671008
type: 'email',
9681009
style: linkStyle,
@@ -1461,7 +1502,7 @@ function (_React$Component) {
14611502
withoutFeedback: true,
14621503
onLongPress: this.onLongPress,
14631504
accessibilityTraits: "text"
1464-
}, this.props.touchableProps), React__default.createElement(ReactNative.View, null, this.renderMessageImage(), this.renderMessageVideo(), this.renderMessageText(),this.renderCustomView(), React__default.createElement(ReactNative.View, {
1505+
}, this.props.touchableProps), React__default.createElement(ReactNative.View, null, this.renderMessageImage(), this.renderMessageVideo(), this.renderMessageText(), this.renderCustomView(), React__default.createElement(ReactNative.View, {
14651506
style: [styles$8[this.props.position].bottom, this.props.bottomContainerStyle[this.props.position]]
14661507
}, this.renderUsername(), this.renderTime(), this.renderTicks())))));
14671508
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"homepage": "https://github.com/johniak/react-web-gifted-chat#readme",
2323
"scripts": {
2424
"lint": "eslint . --ext .js,.jsx",
25+
"prepublish": "export BABEL_ENV='production' && rm -rf ./dist && mkdir dist && rollup -c -i src/index.js -o dist/index.js",
2526
"compile": "export BABEL_ENV='production' && rm -rf ./dist && mkdir dist && rollup -c -i src/index.js -o dist/index.js"
2627
},
2728
"devDependencies": {

src/Bubble.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,10 @@ export default class Bubble extends React.Component {
172172
{...this.props.touchableProps}
173173
>
174174
<View>
175-
{this.renderCustomView()}
176175
{this.renderMessageImage()}
177176
{this.renderMessageVideo()}
178177
{this.renderMessageText()}
178+
{this.renderCustomView()}
179179
<View style={[styles[this.props.position].bottom, this.props.bottomContainerStyle[this.props.position]]}>
180180
{this.renderUsername()}
181181
{this.renderTime()}

src/MessageText.js

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,26 +45,41 @@ export default class MessageText extends React.Component {
4545
onPhonePress(phone) {
4646
const options = ['Call', 'Text', 'Cancel'];
4747
const cancelButtonIndex = options.length - 1;
48-
this.context.actionSheet().showActionSheetWithOptions({
49-
options,
50-
cancelButtonIndex,
51-
},
52-
(buttonIndex) => {
53-
// switch (buttonIndex) {
54-
// case 0:
55-
// Communications.phonecall(phone, true);
56-
// break;
57-
// case 1:
58-
// Communications.text(phone);
59-
// break;
60-
// }
61-
});
48+
// this.context.actionSheet().showActionSheetWithOptions({
49+
// options,
50+
// cancelButtonIndex,
51+
// },
52+
// (buttonIndex) => {
53+
// // switch (buttonIndex) {
54+
// // case 0:
55+
// // Communications.phonecall(phone, true);
56+
// // break;
57+
// // case 1:
58+
// // Communications.text(phone);
59+
// // break;
60+
// // }
61+
// });
6262
}
6363

6464
onEmailPress(email) {
6565
// Communications.email(email, null, null, null, null);
6666
}
6767

68+
renderText = (matchingString, matches) => {
69+
const { members, profile } = this.props;
70+
let name = matches[4]
71+
if (profile && profile.username == name) {
72+
name = profile.name
73+
}
74+
else {
75+
let user = members.find(user=> user.id==matches[4]);
76+
if(user){
77+
name=user.display;
78+
}
79+
}
80+
return `${matches[2]}${name}`;
81+
}
82+
6883
render() {
6984
const linkStyle = StyleSheet.flatten([styles[this.props.position].link, this.props.linkStyle[this.props.position]]);
7085
return (
@@ -77,6 +92,8 @@ export default class MessageText extends React.Component {
7792
]}
7893
parse={[
7994
...this.props.parsePatterns(linkStyle),
95+
96+
{ type:'mention', style: linkStyle, onPress: null, renderText: this.renderText },
8097
{ type: 'url', style: linkStyle, onPress: this.onUrlPress },
8198
{ type: 'phone', style: linkStyle, onPress: this.onPhonePress },
8299
{ type: 'email', style: linkStyle, onPress: this.onEmailPress },

src/ParsedText.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
55
import TextExtraction from './TextExtraction';
66

77
const PATTERNS = {
8+
mention: /((.)\[([^[]*)]\(([^(^)]*)\))/gi,
89
url: /(https?:\/\/|www\.)[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/i,
910
phone: /[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}/,
1011
email: /\S+@\S+\.\S+/,
@@ -48,7 +49,6 @@ class ParsedText extends React.Component {
4849
}
4950
patternOption.pattern = PATTERNS[type];
5051
}
51-
5252
return patternOption;
5353
});
5454
}

src/Send.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ export default function Send({ text, containerStyle, onSend, children, textStyle
1515
accessibilityLabel="send"
1616
style={{ ...styles.container, ...containerStyle }}
1717
onPress={() => {
18-
console.log('asdasdasd')
1918
onSend({ text: text.trim() }, true);
2019
}}
2120
accessibilityTraits="button"

src/TextExtraction.js

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,62 @@ class TextExtraction {
1515
* @return {Object[]} - props for all the parts of the text
1616
*/
1717
parse() {
18-
let parsedTexts = [{children: this.text}];
18+
let parsedTexts = [{ children: this.text }];
1919
this.patterns.forEach((pattern) => {
2020
let newParts = [];
2121

22+
const tmp = pattern.nonExhaustiveModeMaxMatchCount || 0;
23+
const numberOfMatchesPermitted = Math.min(
24+
Math.max(Number.isInteger(tmp) ? tmp : 0, 0) ||
25+
Number.POSITIVE_INFINITY,
26+
Number.POSITIVE_INFINITY,
27+
);
28+
29+
let currentMatches = 0;
30+
2231
parsedTexts.forEach((parsedText) => {
2332
// Only allow for now one parsing
2433
if (parsedText._matched) {
2534
newParts.push(parsedText);
26-
2735
return;
2836
}
2937

30-
let parts = [];
38+
let parts = [];
3139
let textLeft = parsedText.children;
32-
33-
while (textLeft) {
34-
let matches = pattern.pattern.exec(textLeft);
35-
36-
if (!matches) { break; }
37-
40+
let indexOfMatchedString = 0;
41+
42+
/** @type {RegExpExecArray} */
43+
let matches;
44+
// Global RegExps are stateful, this makes it start at 0 if reused
45+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec
46+
pattern.pattern.lastIndex = 0;
47+
while (textLeft && (matches = pattern.pattern.exec(textLeft))) {
3848
let previousText = textLeft.substr(0, matches.index);
49+
indexOfMatchedString = matches.index;
50+
51+
if (++currentMatches > numberOfMatchesPermitted) {
52+
// Abort if we've exhausted our number of matches
53+
break;
54+
}
3955

40-
parts.push({children: previousText});
56+
parts.push({ children: previousText });
4157

42-
parts.push(this.getMatchedPart(pattern, matches[0], matches));
58+
parts.push(
59+
this.getMatchedPart(
60+
pattern,
61+
matches[0],
62+
matches,
63+
indexOfMatchedString,
64+
),
65+
);
4366

4467
textLeft = textLeft.substr(matches.index + matches[0].length);
68+
indexOfMatchedString += matches[0].length - 1;
69+
// Global RegExps are stateful, this makes it operate on the "remainder" of the string
70+
pattern.pattern.lastIndex = 0;
4571
}
4672

47-
parts.push({children: textLeft});
73+
parts.push({ children: textLeft });
4874

4975
newParts.push(...parts);
5076
});
@@ -53,9 +79,9 @@ class TextExtraction {
5379
});
5480

5581
// Remove _matched key.
56-
parsedTexts.forEach((parsedText) => delete(parsedText._matched));
82+
parsedTexts.forEach((parsedText) => delete parsedText._matched);
5783

58-
return parsedTexts.filter(t => !!t.children);
84+
return parsedTexts.filter((t) => !!t.children);
5985
}
6086

6187
// private

0 commit comments

Comments
 (0)