Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/client/components/editor/submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export const Submit = props => {
return h('div.editor-submit', [
h(Popover, {
tippy: {
html: h(TaskView, { document, bus, controller, emitter } )
html: h(TaskView, { document, bus, controller, emitter } ),
sticky: true
}
}, [
h('button.editor-submit-button', {
Expand Down
135 changes: 134 additions & 1 deletion src/client/components/tasks.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import _ from 'lodash';
import DataComponent from './data-component';
import h from 'react-hyperscript';
import { Component } from 'react';
import React from 'react';

import Document from '../../model/document';
import { ENTITY_TYPE } from '../../model/element/entity-type';
Expand All @@ -23,6 +25,122 @@ let unbindEleEvts = (ele, cb) => {
});
};

class TextEditableComponent extends Component {

constructor( props ) {
super( props );
this.textInput = React.createRef();
this.placeholderText = props.placeholder || '';
this.defaultValue = props.value || this.placeholderText;
this.state = {
editText: this.defaultValue,
submittedText: this.defaultValue,
submitted: !!props.value || false
};
this.wait = props.autosubmit || 0;
this.debounceSubmit = _.debounce( this.handleSubmit.bind( this ), this.wait );
}

handleChange ( e ) {
this.setState({
submitted: false,
editText: e.target.value
});
if( this.props.autosubmit ) this.debounceSubmit();
}

handleSubmit () {
const { editText } = this.state;
const { cb } = this.props;
const newValue = editText && editText.trim();
return new Promise( resolve => {
this.setState({
submittedText: newValue,
submitted: !!newValue
}, resolve( newValue ) );
})
.then( cb )
.catch( () => {} );
}

reset() {
const { submittedText } = this.state;
this.setState({
editText: submittedText
});
}

componentDidMount() {
const { autofocus } = this.props;
if( autofocus ){
this.textInput.current.focus();
this.textInput.current.select();
}
}

handleKeyDown ( e ) {
if ( e.key === 'Escape' ) {
this.reset();
this.textInput.current.blur();
} else if ( e.key === 'Enter' ) {
this.textInput.current.blur();
this.handleSubmit( e );
}
}

handleBlur () {
const { editText } = this.state;
const isPlaceholderText = editText === this.placeholderText;

if ( !isPlaceholderText || !this.placeholderText ) {
this.handleSubmit();
}

if( this.placeholderText && !editText ){
this.setState({ editText: this.placeholderText });
}
}

handleFocus ( ) {
const { editText } = this.state;
const isPlaceholderText = !!this.placeholderText && editText === this.placeholderText;
if( isPlaceholderText ){
this.setState({ editText: '' });
}
this.textInput.current.select();
}

render() {
const { label, className } = this.props;
const { editText, submitted } = this.state;

return h('div.text-editable', className, [
h('label', {
htmlFor: `text-editable-${label}`
}, [
label
]),
h('input', {
type: 'text',
className: makeClassList({
'placeholder': editText == this.placeholderText
}),
value: editText,
ref: this.textInput,
onChange: e => this.handleChange( e ),
onFocus: e => this.handleFocus( e ),
onBlur: e => this.handleBlur( e ),
onKeyDown: e => this.handleKeyDown( e ),
id: `text-editable-${label}`,
}),
h( 'i.material-icons', {
className: makeClassList({ 'show': submitted })
}, 'check_circle_outline' )
]);
}
}


export class TaskShare extends Component {
constructor( props ){
super( props );
Expand Down Expand Up @@ -243,6 +361,7 @@ class TaskView extends DataComponent {
} else {
const publicUrl = `${BASE_URL}${document.publicUrl()}`;
const imageUrl = `${BASE_URL}/api${document.publicUrl()}.png`;
const provided = document.provided();
return h('div.task-view', [
h('div.task-view-done', [
h('div.task-view-done-title', 'Thank you!' ),
Expand Down Expand Up @@ -280,6 +399,20 @@ class TaskView extends DataComponent {
])
])
])
]),
h('hr'),
h('div.task-view-done-section', [
h('div.task-view-done-section-body', [
h('p', 'Optional info'),
h( TextEditableComponent, {
label: 'Name:',
value: _.get( provided, 'name' ),
autofocus: true,
placeholder: '',
autosubmit: 1000,
cb: name => document.provided({ name })
})
])
])
])
]);
Expand All @@ -288,4 +421,4 @@ class TaskView extends DataComponent {
}


export { TaskView };
export { TaskView, TextEditableComponent };
30 changes: 30 additions & 0 deletions src/styles/tasks.css
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,33 @@
}
}

.text-editable {
text-align: left;
height: 2em;
}

.text-editable input[type="text"] {
transition: none;
}

.text-editable input[type="text"]:focus {
border: 2px solid var(--brandColor);
}

.text-editable input[type="text"].placeholder {
color: var(--fadedColor);
}

.text-editable label {
display: inline-block;
margin: auto 0.5em;
}

.text-editable i {
visibility: hidden;
}

.text-editable i.show {
margin: auto 0.5em;
visibility: initial;
}