forms seem to work now
This commit is contained in:
+16
-5
@@ -558,10 +558,23 @@ table.permission-editor td.checkbox {
|
|||||||
min-width: 8rem;
|
min-width: 8rem;
|
||||||
}
|
}
|
||||||
.bot-form.hlist {
|
.bot-form.hlist {
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
.bot-form div {
|
||||||
|
min-height: 2rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
/* Nested bot forms should have not border */
|
||||||
|
.bot-form .bot-form {
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bot-form div {
|
/*
|
||||||
|
Form element with non-interactive content
|
||||||
|
needs padding.
|
||||||
|
*/
|
||||||
|
.bot-form div.dft {
|
||||||
|
padding: 0.25rem 1rem;
|
||||||
min-height: 2rem;
|
min-height: 2rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
@@ -664,7 +677,7 @@ i.search {
|
|||||||
.alert-box.info {
|
.alert-box.info {
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: #e1f5fe;
|
background-color: #e1f5fe;
|
||||||
border-bottom: 1px solid #4fc3f7;
|
border-bottom: 1px solid #b3e5fc;
|
||||||
color: #0288d1;
|
color: #0288d1;
|
||||||
}
|
}
|
||||||
.alert-box .cancel .material-icons {
|
.alert-box .cancel .material-icons {
|
||||||
@@ -1155,7 +1168,6 @@ i.search {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-box .right {
|
.chat-box .right {
|
||||||
@@ -1171,7 +1183,6 @@ i.search {
|
|||||||
padding: 0.75rem 0.5rem 0.75rem 1.25rem;
|
padding: 0.75rem 0.5rem 0.75rem 1.25rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -7,6 +7,7 @@ import Tinode from 'tinode-sdk';
|
|||||||
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
||||||
import CheckBox from '../widgets/checkbox.jsx';
|
import CheckBox from '../widgets/checkbox.jsx';
|
||||||
import ContactList from '../widgets/contact-list.jsx';
|
import ContactList from '../widgets/contact-list.jsx';
|
||||||
|
import ErrorPanel from '../widgets/error-panel.jsx';
|
||||||
import GroupManager from '../widgets/group-manager.jsx';
|
import GroupManager from '../widgets/group-manager.jsx';
|
||||||
import InPlaceEdit from '../widgets/in-place-edit.jsx';
|
import InPlaceEdit from '../widgets/in-place-edit.jsx';
|
||||||
import MenuCancel from '../widgets/menu-cancel.jsx';
|
import MenuCancel from '../widgets/menu-cancel.jsx';
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
import Tinode from 'tinode-sdk';
|
import Tinode from 'tinode-sdk';
|
||||||
|
const Drafty = Tinode.Drafty;
|
||||||
|
|
||||||
import ChatMessage from '../widgets/chat-message.jsx';
|
import ChatMessage from '../widgets/chat-message.jsx';
|
||||||
import ErrorPanel from '../widgets/error-panel.jsx';
|
import ErrorPanel from '../widgets/error-panel.jsx';
|
||||||
@@ -62,6 +63,7 @@ class MessagesView extends React.Component {
|
|||||||
this.handleInfoReceipt = this.handleInfoReceipt.bind(this);
|
this.handleInfoReceipt = this.handleInfoReceipt.bind(this);
|
||||||
this.handleImagePreview = this.handleImagePreview.bind(this);
|
this.handleImagePreview = this.handleImagePreview.bind(this);
|
||||||
this.handleCloseImagePreview = this.handleCloseImagePreview.bind(this);
|
this.handleCloseImagePreview = this.handleCloseImagePreview.bind(this);
|
||||||
|
this.handleFormResponse = this.handleFormResponse.bind(this);
|
||||||
this.handleContextClick = this.handleContextClick.bind(this);
|
this.handleContextClick = this.handleContextClick.bind(this);
|
||||||
this.handleShowContextMenuMessage = this.handleShowContextMenuMessage.bind(this);
|
this.handleShowContextMenuMessage = this.handleShowContextMenuMessage.bind(this);
|
||||||
this.handleBackNavigation = this.handleBackNavigation.bind(this);
|
this.handleBackNavigation = this.handleBackNavigation.bind(this);
|
||||||
@@ -349,6 +351,30 @@ class MessagesView extends React.Component {
|
|||||||
this.setState({ imagePreview: null });
|
this.setState({ imagePreview: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleFormResponse(action, text, data) {
|
||||||
|
if (action == 'pub') {
|
||||||
|
this.props.sendMessage(Drafty.attachJSON(Drafty.parse(text), data));
|
||||||
|
} else if (action == 'url') {
|
||||||
|
const url = new URL(data.ref);
|
||||||
|
let params = url.searchParams;
|
||||||
|
for (let key in data.resp) {
|
||||||
|
if (data.resp.hasOwnProperty(key)) {
|
||||||
|
params.set(key, data.resp[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
['name', 'seq'].map(function(key) {
|
||||||
|
if (data[key]) {
|
||||||
|
params.set(key, data[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
params.set('uid', this.props.myUserId);
|
||||||
|
url.search = params;
|
||||||
|
window.open(url, '_blank');
|
||||||
|
} else {
|
||||||
|
console.log("Unknown action in form", action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleContextClick(e) {
|
handleContextClick(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -376,11 +402,10 @@ class MessagesView extends React.Component {
|
|||||||
const {formatMessage} = this.props.intl;
|
const {formatMessage} = this.props.intl;
|
||||||
|
|
||||||
let component;
|
let component;
|
||||||
|
|
||||||
if (this.state.topic) {
|
if (this.state.topic) {
|
||||||
|
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||||
|
const groupTopic = topic.getType() == 'grp';
|
||||||
let messageNodes = [];
|
let messageNodes = [];
|
||||||
let topic = this.props.tinode.getTopic(this.state.topic);
|
|
||||||
let groupTopic = topic.getType() == 'grp';
|
|
||||||
let previousFrom = null;
|
let previousFrom = null;
|
||||||
let chatBoxClass = null;
|
let chatBoxClass = null;
|
||||||
for (let i=0; i<this.state.messages.length; i++) {
|
for (let i=0; i<this.state.messages.length; i++) {
|
||||||
@@ -403,12 +428,12 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
previousFrom = msg.from;
|
previousFrom = msg.from;
|
||||||
|
|
||||||
let isReply = !(msg.from == this.props.myUserId);
|
const isReply = !(msg.from == this.props.myUserId);
|
||||||
let deliveryStatus = topic.msgStatus(msg);
|
const deliveryStatus = topic.msgStatus(msg);
|
||||||
|
|
||||||
let userName, userAvatar, userFrom;
|
let userName, userAvatar, userFrom;
|
||||||
if (groupTopic) {
|
if (groupTopic) {
|
||||||
let user = topic.userDesc(msg.from);
|
const user = topic.userDesc(msg.from);
|
||||||
if (user && user.public) {
|
if (user && user.public) {
|
||||||
userName = user.public.fn;
|
userName = user.public.fn;
|
||||||
userAvatar = makeImageUrl(user.public.photo);
|
userAvatar = makeImageUrl(user.public.photo);
|
||||||
@@ -430,6 +455,7 @@ class MessagesView extends React.Component {
|
|||||||
viewportWidth={this.props.viewportWidth}
|
viewportWidth={this.props.viewportWidth}
|
||||||
showContextMenu={this.handleShowContextMenuMessage}
|
showContextMenu={this.handleShowContextMenuMessage}
|
||||||
onImagePreview={this.handleImagePreview}
|
onImagePreview={this.handleImagePreview}
|
||||||
|
onFormResponse={this.handleFormResponse}
|
||||||
onError={this.props.onError}
|
onError={this.props.onError}
|
||||||
key={msg.seq} />
|
key={msg.seq} />
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class SidepanelView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let onCancel;
|
let onCancel;
|
||||||
if (view != 'login') {
|
if (['login', 'contacts'].indexOf(view) == -1) {
|
||||||
onCancel = this.props.onCancel;
|
onCancel = this.props.onCancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import FileProgress from './file-progress.jsx';
|
import FileProgress from './file-progress.jsx';
|
||||||
|
import { bytesToHumanSize } from '../lib/strformat.js';
|
||||||
|
|
||||||
export default class Attachment extends React.Component {
|
export default class Attachment extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|||||||
@@ -39,7 +39,22 @@ export default class ChatMessage extends React.Component {
|
|||||||
|
|
||||||
handleFormButtonClick(e) {
|
handleFormButtonClick(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log(e.target);
|
const data = {
|
||||||
|
seq: this.props.seq
|
||||||
|
};
|
||||||
|
data.resp = {};
|
||||||
|
if (e.target.dataset.name) {
|
||||||
|
data.resp[e.target.dataset.name] = e.target.dataset.val ? e.target.dataset.val :
|
||||||
|
e.target.dataset.val === undefined ? 1 : '' + e.target.dataset.val;
|
||||||
|
}
|
||||||
|
if (e.target.dataset.act == 'url') {
|
||||||
|
data.ref = '' + e.target.dataset.ref;
|
||||||
|
}
|
||||||
|
if (e.target.dataset.formname) {
|
||||||
|
data.name = '' + e.target.dataset.formname;
|
||||||
|
}
|
||||||
|
const text = e.target.dataset.title || 'unknown';
|
||||||
|
this.props.onFormResponse(e.target.dataset.act, text, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleContextClick(e) {
|
handleContextClick(e) {
|
||||||
@@ -68,6 +83,11 @@ export default class ChatMessage extends React.Component {
|
|||||||
const attachments = [];
|
const attachments = [];
|
||||||
if (this.props.mimeType == Drafty.getContentType()) {
|
if (this.props.mimeType == Drafty.getContentType()) {
|
||||||
Drafty.attachments(content, function(att, i) {
|
Drafty.attachments(content, function(att, i) {
|
||||||
|
if (att.mime == 'application/json') {
|
||||||
|
// Don't show json objects as attachments.
|
||||||
|
// They are not meant for users.
|
||||||
|
return;
|
||||||
|
}
|
||||||
attachments.push(<Attachment
|
attachments.push(<Attachment
|
||||||
tinode={this.props.tinode}
|
tinode={this.props.tinode}
|
||||||
downloadUrl={Drafty.getDownloadUrl(att)}
|
downloadUrl={Drafty.getDownloadUrl(att)}
|
||||||
@@ -147,6 +167,11 @@ function draftyFormatter(style, data, values, key) {
|
|||||||
case 'FM':
|
case 'FM':
|
||||||
// Form
|
// Form
|
||||||
attr.className = 'bot-form' + ((data && data.layout) ? ' ' + data.layout : '');
|
attr.className = 'bot-form' + ((data && data.layout) ? ' ' + data.layout : '');
|
||||||
|
// console.log(data, attr);
|
||||||
|
break;
|
||||||
|
case 'FE':
|
||||||
|
// Form element formatting is dependent on element content.
|
||||||
|
attr.className = data && data.dftp ? data.dftp : '';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return React.createElement(el, attr, values);
|
return React.createElement(el, attr, values);
|
||||||
|
|||||||
@@ -87,9 +87,8 @@ class ContactList extends React.Component {
|
|||||||
{contactNodes}
|
{contactNodes}
|
||||||
</ul>
|
</ul>
|
||||||
:
|
:
|
||||||
<div className="center-medium-text">
|
<div className="center-medium-text" dangerouslySetInnerHTML={{__html: this.props.emptyListMessage}} />
|
||||||
{this.props.emptyListMessage}
|
}
|
||||||
</div>}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { defineMessages, injectIntl } from 'react-intl';
|
|||||||
import { Drafty } from 'tinode-sdk';
|
import { Drafty } from 'tinode-sdk';
|
||||||
|
|
||||||
import { KEYPRESS_DELAY, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE } from '../config.js';
|
import { KEYPRESS_DELAY, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE } from '../config.js';
|
||||||
import { SUPPORTED_IMAGE_FORMATS, filePasted, imageFileToBase64, imageFileScaledToBase64 } from '../lib/blob-helpers.js';
|
import { SUPPORTED_IMAGE_FORMATS, filePasted, fileToBase64, imageFileToBase64, imageFileScaledToBase64 } from '../lib/blob-helpers.js';
|
||||||
import { bytesToHumanSize } from '../lib/strformat.js';
|
import { bytesToHumanSize } from '../lib/strformat.js';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|||||||
+87
-24
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user