frc-ui
Version:
React Web UI
420 lines (419 loc) • 18.1 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import React from 'react';
import classNames from 'classnames';
import { v1 } from 'uuid';
import { Consumer } from '../common/Hoc';
import Inset from '../common/ChatInsetContent';
import { FsType, LocalStorageKey, MessageType, PermissionEnum, TrendType } from '../interfaces';
import Button from './Button';
import { getLocalStorageItem } from '../common';
let Send = class Send extends React.PureComponent {
constructor(props) {
super(props);
this.urlReg = /^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+/;
this.textMaxFreq = 10;
this.textTimeWindow = 10;
this.textSendRecord = [];
this.saveRef = (name) => (ref) => {
this[name] = ref;
};
this.getMessage = () => {
if (!this.chatMessage)
return [];
const childNodes = this.chatMessage.childNodes;
const length = childNodes.length;
let message = [];
for (let i = 0; i < length; i++) {
const node = childNodes[i];
if (node.nodeName === '#text') {
message = this.analysisText(node['textContent'], message);
}
else {
message.push({ type: node['eleType'], content: node['content'] });
}
}
this.setState({ textLength: 0 });
return message;
};
this.analysisText = (text, message = []) => {
if (!text)
return message;
const arr = (text || '').split(' ');
arr &&
arr.map((t) => {
message.push({ type: this.urlReg.test(t) ? MessageType.LINK : MessageType.TEXT, content: t });
message.push({ type: MessageType.TEXT, content: ' ' });
});
return message;
};
this.initColorIndex = (permission) => {
const localStorage = window.localStorage;
let danmakuColor = '#ffffff';
if (permission && localStorage) {
const colorValue = localStorage.getItem('danmakuColor');
if (!colorValue && colorValue !== '') {
return colorValue;
}
}
return danmakuColor;
};
this.send = (message = []) => {
if (!message || message.length === 0)
return;
const { Socket, user, permission, channel, isAnonymous, fontSize, anonymousName, locale, trendType, isGag, setName } = this.props;
const { often } = this.state;
const has = (permission || []).some((p) => p === PermissionEnum.CHAT_ROOM);
if (isGag || often || !has) {
return;
}
const per = permission || [];
const fontSizePermission = per.some((p) => p === PermissionEnum.DANMAKU_FONT);
const colorPermission = per.some((p) => p === PermissionEnum.DANMAKU_COLOR);
const chatMessage = {
id: v1(),
username: user && user.username,
isAnonymous,
channel,
userId: user && user.userId,
loginName: user && user.username,
showName: user && user.companyName + '-' + user.name,
message,
style: {
color: this.initColorIndex(colorPermission),
fontSize: (fontSizePermission ? fontSize : 20) + 'px'
}
};
if (anonymousName && isAnonymous) {
if (typeof setName === 'function') {
chatMessage.showName = setName(Object.assign(Object.assign({}, user), { trendType, isAnonymous, anonymousName }));
}
else {
chatMessage.showName = ((locale && locale.trendType[trendType || TrendType.NONE]) || '') + anonymousName;
}
}
if (Socket)
Socket.send('chat', chatMessage);
};
this.moveCursor = () => {
if (!this.chatMessage)
return;
this.chatMessage.focus();
if (window.getSelection && this.chatMessage.lastChild) {
let sel = window.getSelection();
let tempRange = document.createRange();
const n = this.chatMessage.lastChild || 0;
tempRange.setStart(n, 0);
if (sel) {
sel.removeAllRanges();
sel.addRange(tempRange);
}
}
};
this.insetContent = (type, content) => {
const { isGag, permission } = this.props;
const { often } = this.state;
const has = (permission || []).some((p) => p === PermissionEnum.CHAT_ROOM);
if (isGag || often || !has) {
return;
}
if (!this.chatMessage)
return;
this.currentType = type;
Inset({ type, content }, this.chatMessage);
this.moveCursor();
};
this.handlePaste = (event) => {
event.preventDefault();
const { emit } = this.props;
const textMaxLength = this.props.textMaxLength || 0;
const { textLength } = this.state;
let cbd = event.clipboardData;
for (let i = 0; i < cbd.items.length; i++) {
let item = cbd.items[i];
if (item.kind === 'file' || item.type.indexOf('image') > -1) {
let blob = item.getAsFile();
if (!blob || blob.size === 0) {
return;
}
const formData = new FormData();
formData.append('file', blob, '');
formData.append('ttl', '1d');
emit &&
emit('chatFile', {
type: FsType.PASTE_IMAGE,
file: formData
});
// blobToDataURL(blob, (url) => this.insetContent(Type.IMAGE, url));
}
else if (item.kind === 'string' && item.type === 'text/plain') {
item.getAsString((str) => {
let regStr = str;
regStr = regStr.replace(/\s+/g, '');
regStr = regStr.replace(/<\/?.+?>/g, '');
regStr = regStr.replace(/[\r\n]/g, '');
if (textLength < textMaxLength) {
let length = regStr.length;
if (textLength + length > textMaxLength) {
const remindLength = textMaxLength - textLength;
let count = 0;
for (let ti = 0; ti < str.length; ti++) {
if (!/\s+/g.test(str[ti]) && !/<\/?.+?>/g.test(str[ti]) && !/[\r\n]/g.test(str[ti])) {
count += 1;
}
if (remindLength <= count) {
str = str.substring(0, ti);
break;
}
}
length = count;
}
this.setState({ textLength: this.state.textLength + length });
str = str.replace(/[\n]/g, ' <br/> ');
const arr = (str || '').split(' ');
(arr || []).map((t) => {
if (t === '<br/>') {
this.insetContent(MessageType.ELEMENT, 'br');
}
else {
this.insetContent(this.urlReg.test(str) ? MessageType.LINK : MessageType.TEXT, t);
}
});
}
});
}
else if (item.kind === 'string' && item.type === 'text/html') {
item.getAsString((str) => {
console.log(str);
});
}
}
};
this.handleKeyDown = (event) => {
const shortcutKey = getLocalStorageItem(LocalStorageKey.shortcutKey, 'EnterSend');
if ((event.ctrlKey || event.metaKey) && event.keyCode === 13) {
if (shortcutKey === 'EnterSend') {
this.handleAddBlank(event);
}
else if (shortcutKey === 'CtrlEnterSend') {
this.handleSend();
}
}
else if (event.keyCode === 13) {
if (shortcutKey === 'EnterSend') {
this.handleSend();
}
else if (shortcutKey === 'CtrlEnterSend') {
this.handleAddBlank(event);
}
}
else {
this.currentType = MessageType.TEXT;
if (this.state.textLength >= (this.props.textMaxLength || 0) &&
event.keyCode !== 8 &&
event.keyCode !== 37 &&
event.keyCode !== 38 &&
event.keyCode !== 39 &&
event.keyCode !== 40) {
event.preventDefault();
}
}
};
this.handleKeyUp = (event) => {
if (!this.chatMessage)
return;
const { textMaxLength } = this.props;
const childNodes = this.chatMessage.childNodes;
let length = 0;
if (!childNodes)
return;
for (let i = 0; i < childNodes.length; i++) {
const node = childNodes[i];
if (!node)
continue;
if (node.nodeName === '#text') {
let tempLength = length + (node.textContent ? node.textContent.length : 0);
if (textMaxLength && tempLength > textMaxLength) {
node.textContent = node.textContent
? node.textContent.substring(0, textMaxLength - length)
: node.textContent;
length = textMaxLength;
}
else {
length = tempLength;
}
}
else if (node['eleType'] === MessageType.TEXT) {
let tempLength = length + (node.textContent ? node.textContent.length : 0);
if (textMaxLength && tempLength > textMaxLength) {
node.textContent = node.textContent
? node.textContent.substring(0, textMaxLength - length)
: node.textContent;
node['content'] = node.textContent;
length = textMaxLength;
}
else {
length = tempLength;
}
}
}
if (textMaxLength && length > textMaxLength) {
event.preventDefault();
}
this.setState({ textLength: length });
};
this.handleAddBlank = (event) => {
event && event.preventDefault();
if (this.currentType === MessageType.TEXT || !this.currentType) {
this.insetContent(MessageType.ELEMENT, 'br');
}
this.insetContent(MessageType.ELEMENT, 'br');
};
this.handleSend = (event) => {
if (event)
event.preventDefault();
const message = this.getMessage();
if (this.checkOften()) {
this.chatMessage && (this.chatMessage.innerHTML = '');
return;
}
setTimeout(() => {
this.chatMessage && (this.chatMessage.innerHTML = '');
}, 16);
this.send(message);
};
this.handleOnClick = () => {
this.closeHistory();
if (this.state.often) {
this.setState({ often: false, textLength: 0 });
}
};
this.handleInput = (event) => {
this.handleKeyUp(event);
};
this.handleFocus = () => {
this.closeHistory();
};
this.closeHistory = () => {
const { emit, success, history } = this.props;
if (emit && history) {
emit('chat', { history: false });
success && success('chatMessage.histories', { payload: 'clear' });
}
};
this.renderCover = (has) => {
const { locale, isGag, prefix } = this.props;
const { often } = this.state;
const cls = `${prefix}-send-cover`;
if (!has)
return React.createElement("div", { className: cls }, locale && locale.noChatPermissionText);
if (isGag)
return React.createElement("div", { className: cls }, locale && locale.gagText);
if (often)
return React.createElement("div", { className: cls }, locale && locale.oftenText);
return null;
};
this.checkOften = (timestamp = new Date().getTime()) => {
const { often } = this.state;
if (this.textSendRecord.length < this.textMaxFreq) {
this.textSendRecord.push(timestamp);
often && this.setState({ often: false });
return false;
}
if (this.textSendRecord.length > 0) {
const first = this.textSendRecord[0];
if ((timestamp - first) / 1000 > this.textTimeWindow) {
this.textSendRecord.push(timestamp);
this.textSendRecord.shift();
often && this.setState({ often: false });
return false;
}
}
!often && this.setState({ often: true });
return true;
};
this.renderInput = (has) => {
const { prefix } = this.props;
const props = {
ref: this.saveRef('chatMessage'),
className: `${prefix}-send-input`,
// contentEditable: has && !isGag && !often,
contentEditable: false,
onKeyDown: this.handleKeyDown,
onKeyUp: this.handleKeyUp,
onPaste: this.handlePaste,
onClick: this.handleOnClick,
onInput: this.handleInput,
onFocus: this.handleFocus
};
return React.createElement("div", Object.assign({}, props, { style: { cursor: 'not-allowed' } }), this.renderCover(has));
};
this.renderTip = (has) => {
const { textMaxLength } = this.props;
const { textLength, often } = this.state;
const { isGag, prefix, locale } = this.props;
if (has && !isGag && !often) {
return (React.createElement("div", { className: `${prefix}-send-text-length` }, locale && locale.inputTip(Math.max((textMaxLength || 0) - textLength, 0))));
}
return null;
};
this.state = {
textLength: 0,
often: false,
textSendRecord: []
};
}
componentWillReceiveProps(nextProps) {
const { emo, textMaxLength, uploadImage } = nextProps;
if (emo && emo !== this.props.emo) {
if (emo.type === 'emo') {
if (textMaxLength && textMaxLength > this.state.textLength) {
this.insetContent(MessageType.EMO, emo.emo);
this.setState({ textLength: this.state.textLength + 1 });
}
}
else if (emo.type === 'collectEmo') {
let message = [{ type: MessageType.GIF, content: emo.emo }];
this.send(message);
}
}
if (uploadImage && uploadImage !== this.props.uploadImage && uploadImage.url) {
this.insetContent(MessageType.IMAGE, uploadImage.url);
}
}
componentDidUpdate(preProps, preState) {
if (preState.often !== this.state.often)
this.moveCursor();
}
render() {
const { prefix, className, permission, isGag } = this.props;
const { often } = this.state;
const has = (permission || []).some((p) => p === PermissionEnum.CHAT_ROOM);
const cls = classNames(`${prefix}-send`, className);
return (React.createElement("div", { className: cls },
this.renderInput(has),
React.createElement("div", { className: `${prefix}-send-bottom` },
this.renderTip(has),
" ",
has && !isGag && !often && React.createElement(Button, { onClick: this.handleSend }))));
}
};
Send = __decorate([
Consumer([
'textMaxLength',
'isGag',
'isAnonymous',
'permission',
'fontSize',
'trendType',
'emo',
'uploadImage',
'history',
'anonymousName'
])
], Send);
export default Send;