1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-22 09:23:13 +01:00

toggable textarea

This commit is contained in:
ddejongh 2015-06-09 13:29:22 +02:00
parent b49f3fe9f2
commit 6563bf97b0
11 changed files with 179 additions and 28 deletions

View File

@ -45,7 +45,7 @@ gulp.task('build', function() {
bundle(false);
});
gulp.task('serve', ['browser-sync', 'lint:watch', 'sass', 'sass:watch', 'copy'], function() {
gulp.task('serve', ['browser-sync', 'sass', 'sass:watch', 'copy'], function() {
bundle(true);
});

View File

@ -14,7 +14,7 @@ let ButtonSubmitOrClose = React.createClass({
<div className="modal-footer">
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
</div>
)
);
}
return (
<div className="modal-footer">

View File

@ -0,0 +1,43 @@
'use strict';
import React from 'react';
import apiUrls from '../../constants/api_urls';
import FormMixin from '../../mixins/form_mixin';
import InputTextAreaToggable from './input_textarea_toggable';
let PersonalNoteForm = React.createClass({
mixins: [FormMixin],
url() {
return apiUrls.note_notes;
},
getFormData() {
return {
bitcoin_id: this.getBitcoinIds().join(),
note: this.refs.personalNote.state.value
};
},
renderForm() {
return (
<form id="personal_note_content" role="form" key="personal_note_content">
<InputTextAreaToggable
ref="personalNote"
className="form-control"
defaultValue={this.props.editions[0].note_from_user}
rows={3}
editable={true}
required=""
onSubmit={this.submit}
/>
</form>
);
}
});
export default PersonalNoteForm;

View File

@ -0,0 +1,72 @@
'use strict';
import React from 'react';
import AlertMixin from '../../mixins/alert_mixin';
import TextareaAutosize from 'react-textarea-autosize';
import Button from 'react-bootstrap/lib/Button';
let InputTextAreaToggable = React.createClass({
mixins: [AlertMixin],
getInitialState() {
return {
value: this.props.defaultValue,
edited: false,
alerts: null // needed in AlertMixin
};
},
handleChange(event) {
this.setState({
value: event.target.value,
edited: true
});
},
reset(){
this.setState(this.getInitialState());
},
submit(){
this.props.onSubmit();
this.setState({edited: false});
},
render() {
let className = 'form-control ascribe-textarea';
let buttons = null;
let textarea = null;
if (this.props.editable && this.state.edited){
buttons = (
<div className="pull-right">
<Button className="ascribe-btn" onClick={this.submit}>Save</Button>
<Button className="ascribe-btn" onClick={this.reset}>Cancel</Button>
</div>
);
}
if (this.props.editable){
className = className + ' ascribe-textarea-editable';
textarea = (
<TextareaAutosize
className={className}
value={this.state.value}
rows={this.props.rows}
required={this.props.required}
onChange={this.handleChange}
placeholder='Write something...' />
);
}
else{
textarea = <pre className="ascribe-pre">{this.state.value}</pre>;
}
let alerts = (this.props.submitted) ? null : this.state.alerts;
return (
<div className="form-group">
{alerts}
{textarea}
{buttons}
</div>
);
}
});
export default InputTextAreaToggable;

View File

@ -8,7 +8,8 @@ import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Button from 'react-bootstrap/lib/Button';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import TextareaAutosize from 'react-textarea-autosize';
import PersonalNoteForm from './ascribe_forms/form_note_personal';
import EditionActions from '../actions/edition_actions';
import AclButtonList from './ascribe_buttons/acl_button_list';
@ -23,7 +24,7 @@ let Edition = React.createClass({
edition: React.PropTypes.object,
currentUser: React.PropTypes.object,
deleteEdition: React.PropTypes.func,
savePersonalNote: React.PropTypes.func
loadEdition: React.PropTypes.func
},
render() {
@ -39,10 +40,14 @@ let Edition = React.createClass({
<a target="_blank" href={'https://www.blocktrail.com/BTC/address/' + this.props.edition.bitcoin_id}>{this.props.edition.bitcoin_id}</a>
);
let hashOfArtwork = (
let hashOfArtwork = (
<a target="_blank" href={'https://www.blocktrail.com/BTC/address/' + this.props.edition.hash_as_address}>{this.props.edition.hash_as_address}</a>
);
let ownerAddress = (
<a target="_blank" href={'https://www.blocktrail.com/BTC/address/' + this.props.edition.btc_owner_address_noprefix}>{this.props.edition.btc_owner_address_noprefix}</a>
);
return (
<Row>
<Col md={6}>
@ -64,8 +69,9 @@ let Edition = React.createClass({
<CollapsibleEditionDetails
title="Personal Note"
iconName="pencil">
<EditionPersonalNote
savePersonalNote={this.props.savePersonalNote}/>
<EditionPersonalNote
handleSuccess={this.props.loadEdition}
edition={this.props.edition}/>
</CollapsibleEditionDetails>
<CollapsibleEditionDetails
@ -92,7 +98,7 @@ let Edition = React.createClass({
value={hashOfArtwork} />
<EditionDetailProperty
label="Owned by SPOOL address"
value="MISSING IN /editions/<id> RESOURCE!" />
value={ownerAddress} />
</CollapsibleEditionDetails>
<CollapsibleEditionDetails
@ -267,7 +273,7 @@ let EditionDetailProperty = React.createClass({
<div className="row ascribe-detail-property">
<div className="row-same-height">
<div className={this.props.labelClassName + ' col-xs-height col-bottom'}>
<div>{ this.props.label }{this.props.separator}</div>
<div>{ this.props.label + this.props.separator}</div>
</div>
<div className={this.props.valueClassName + ' col-xs-height col-bottom'}>
<div>{ this.props.value }</div>
@ -304,7 +310,7 @@ let EditionDetailHistoryIterator = React.createClass({
let EditionPersonalNote = React.createClass({
propTypes: {
savePersonalNote: React.PropTypes.func
edition: React.PropTypes.object
},
prepareSavePersonalNote() {
@ -316,14 +322,9 @@ let EditionPersonalNote = React.createClass({
return (
<Row>
<Col md={12} className="ascribe-edition-personal-note">
<TextareaAutosize
ref="personalNote"
className="form-control"
rows={3}
placeholder='Write something...' />
<Button
onClick={this.prepareSavePersonalNote}
className="pull-right">Save</Button>
<PersonalNoteForm
handleSuccess={this.props.handleSuccess}
editions={[this.props.edition]} />
</Col>
</Row>
);

View File

@ -4,6 +4,9 @@ import React from 'react';
import { mergeOptions } from '../utils/general_utils';
import apiUrls from '../constants/api_urls';
import fetch from '../utils/fetch';
import EditionActions from '../actions/edition_actions';
import EditionStore from '../stores/edition_store';
import UserActions from '../actions/user_actions';
@ -40,9 +43,8 @@ let EditionContainer = React.createClass({
// Delete Edition from server
},
savePersonalNote(note) {
console.log(note);
// Save personalNote to server
loadEdition() {
EditionActions.fetchOne(this.props.params.editionId);
},
render() {
@ -52,7 +54,7 @@ let EditionContainer = React.createClass({
edition={this.state.edition}
currentUser={this.state.currentUser}
deleteEdition={this.deleteEdition}
savePersonalNote={this.savePersonalNote}/>
loadEdition={this.loadEdition}/>
);
} else {
return (

View File

@ -13,7 +13,8 @@ let apiUrls = {
'ownership_loans': AppConstants.baseUrl + 'ownership/loans/',
'ownership_consigns': AppConstants.baseUrl + 'ownership/consigns/',
'ownership_unconsigns': AppConstants.baseUrl + 'ownership/unconsigns/',
'ownership_unconsigns_request': AppConstants.baseUrl + 'ownership/unconsigns/request/'
'ownership_unconsigns_request': AppConstants.baseUrl + 'ownership/unconsigns/request/',
'note_notes': AppConstants.baseUrl + 'note/notes/'
};
export default apiUrls;

View File

@ -1,8 +1,8 @@
'use strict';
let constants = {
//'baseUrl': 'http://localhost:8000/api/',
'baseUrl': 'http://staging.ascribe.io/api/',
'baseUrl': 'http://localhost:8000/api/',
//'baseUrl': 'http://staging.ascribe.io/api/',
'debugCredentialBase64': 'ZGltaUBtYWlsaW5hdG9yLmNvbTowMDAwMDAwMDAw', // dimi@mailinator:0000000000
'aclList': ['edit', 'consign', 'transfer', 'loan', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection']
};

View File

@ -14,22 +14,32 @@ export const FormMixin = {
},
submit(e) {
e.preventDefault();
if (e) {
e.preventDefault();
}
this.setState({submitted: true});
this.clearErrors();
fetch
.post(this.url(), { body: this.getFormData() })
.then(() => this.props.handleSuccess())
.then(() => this.handleSuccess() )
.catch(this.handleError);
},
clearErrors(){
for (var ref in this.refs){
this.refs[ref].clearAlerts();
if ('clearAlerts' in this.refs[ref]){
this.refs[ref].clearAlerts();
}
}
this.setState({errors: []});
},
handleSuccess(){
if ('handleSuccess' in this.props){
this.props.handleSuccess();
}
},
handleError(err){
if (err.json) {
for (var input in err.json.errors){

View File

@ -0,0 +1,21 @@
.ascribe-textarea {
border: none;
box-shadow: none;
margin-bottom: 1em;
}
.ascribe-textarea-editable:hover {
border: 1px solid #AAA;
}
.ascribe-pre{
word-break: break-word;
/* white-space: pre-wrap; */
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
/* word-wrap: break-word; */
font-family: inherit;
text-align: justify;
background-color: white;
}

View File

@ -10,6 +10,7 @@
@import 'ascribe_piece_list_bulk_modal';
@import 'ascribe_piece_list_toolbar';
@import 'ascribe_edition';
@import 'ascribe_textarea';
@import 'ascribe_media_player';
@import 'offset_right';