Skip to content

Commit

Permalink
Merge pull request #215 from Codeminer42/attachments-to-react-component
Browse files Browse the repository at this point in the history
Converts attachment input to react component
  • Loading branch information
adbatista committed Jul 14, 2017
2 parents 4d22023 + 8076470 commit f47b592
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 51 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Changed
- Story tasks to react components
- Story attachments input to react component

### Fixed
- Fixing compatibility of docker-composer with webpack
Expand Down
107 changes: 107 additions & 0 deletions app/assets/javascripts/components/story/StoryAttachment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from 'react';

class StoryAttachment extends React.Component {
constructor(props) {
super(props);
this.saveInput = (input) => { this.filesInput = input };
this.random = (Math.floor(Math.random() * 10000) + 1);
this.progressElementId = "documents_progress_" + this.random;
this.finishedElementId = "documents_finished_" + this.random;
this.attachinaryContainerId = "attachinary_container_" + this.random;
}

componentDidMount() {
const $filesInput = $(this.filesInput);
$filesInput.off('fileuploadprogressall');
$filesInput.on('fileuploadprogressall', (function(_this, _progressElementId, _finishedElementId) {
return function(e, data) {
var $progress = $('#' + _progressElementId);
if ( $progress.is(":hidden") ) {
$progress.show();
}

var progress = parseInt(data.loaded / data.total * 100, 10);
$progress.css('width', progress + "%");

if (progress == 100) {
$progress.css('width', "1px");
$progress.hide();

$('#' + _finishedElementId).show();
}
};
})(this, this.progressElementId, this.finishedElementId));
}

makeAttachinaryProps(name, progress_element_id, finished_element_id, attachinary_container_id, filesModel) {
const field_name = name + ( ATTACHINARY_OPTIONS.html.multiple ? '[]' : '' );
let files = filesModel;

if(files) {
files = files.map(function(d) { return d.file });
}

const options = $.extend(ATTACHINARY_OPTIONS.attachinary, {
files_container_selector: '#' + attachinary_container_id,
'files': files
});
const dataAttachinary = JSON.stringify(options);
const dataFormData = JSON.stringify(ATTACHINARY_OPTIONS.html.data.form_data);
const dataUrl = ATTACHINARY_OPTIONS.html.data.url;
const multiple = (ATTACHINARY_OPTIONS.html.multiple) ? 'multiple' : '';

return {
dataAttachinary: dataAttachinary,
dataFormData: dataFormData,
dataUrl: dataUrl,
multiple: multiple
};
}

renderAttachmentInput() {
const { name, filesModel } = this.props;
let attachinary = this.makeAttachinaryProps(
'documents',
this.progressElementId,
this.finishedElementId,
this.attachinaryContainerId,
filesModel
);

return(
<input
type='file'
name={name}
className='attachinary-input'
ref={this.saveInput}
multiple={attachinary.multiple}
data-attachinary={attachinary.dataAttachinary}
data-form-data={attachinary.dataFormData}
data-url={attachinary.dataUrl}
/>
);
}

renderProgressBar() {
return(
<div
id={this.progressElementId}
className='attachinary_progress_bar'
/>
);
}

render() {
const { name, isReadonly } = this.props;
return(
<div className="uploads">
<label htmlFor={name}>{ I18n.t(`story.${name}`) }</label>
{ (!isReadonly) ? this.renderAttachmentInput() : null }
{ (!isReadonly) ? this.renderProgressBar() : null }
<div id={this.attachinaryContainerId} />
</div>
);
}
}

export default StoryAttachment;
36 changes: 0 additions & 36 deletions app/assets/javascripts/views/form_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,6 @@ module.exports = Backbone.View.extend({
return el;
},

fileField: function(name, progress_element_id, finished_element_id, attachinary_container_id) {
var field_name = name + ( ATTACHINARY_OPTIONS['html']['multiple'] ? '[]' : '' );
var files = this.model.get('documents');
if(files) {
files = files.map(function(d) { return d.file });
}
var options = $.extend(ATTACHINARY_OPTIONS['attachinary'], {
files_container_selector: '#' + attachinary_container_id, 'files': files });
var el = this.make('input', {name: field_name, type: "file", class: 'attachinary-input',
'data-attachinary': JSON.stringify(options),
'data-form-data': JSON.stringify(ATTACHINARY_OPTIONS['html']['data']['form_data']),
'data-url': ATTACHINARY_OPTIONS['html']['data']['url'],
'multiple': ( ATTACHINARY_OPTIONS['html']['multiple'] ? 'multiple' : '' ),
});

$(el).bind('fileuploadprogressall', (function(_this, _progress_element_id, _finished_element_id) {
return function(e, data) {
var el_progress = $('#' + _progress_element_id);
if ( el_progress.is(":hidden") )
el_progress.show();

var progress = parseInt(data.loaded / data.total * 100, 10);
el_progress.css('width', progress + "%");

if (progress == 100) {
el_progress.css('width', "1px");
el_progress.hide();

$('#' + _finished_element_id).show();
}
};
})(this, progress_element_id, finished_element_id));
this.bindElementToAttribute(el, name);
return el;
},

select: function(name, select_options, options) {
if (typeof options == 'undefined') {
options = {};
Expand Down
32 changes: 17 additions & 15 deletions app/assets/javascripts/views/story_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import NoteForm from 'components/notes/NoteForm';
import StoryLabels from 'components/story/StoryLabels';
import StoryTasks from 'components/story/StoryTasks';
import TaskForm from 'components/tasks/TaskForm';
import StoryAttachment from 'components/story/StoryAttachment';

var Clipboard = require('clipboard');

Expand Down Expand Up @@ -405,21 +406,9 @@ module.exports = FormView.extend({

this.$el.append(
this.makeFormControl(function(div) {
var random = (Math.floor(Math.random() * 10000) + 1);
var progress_element_id = "documents_progress_" + random;
var finished_element_id = "documents_finished_" + random;
var attachinary_container_id = "attachinary_container_" + random;

$(div).append(this.label('attachments', I18n.t('story.attachments')));
$(div).addClass('uploads');
if(!this.isReadonly()) {
$(div).append(this.fileField("documents", progress_element_id, finished_element_id, attachinary_container_id));
$(div).append("<div id='" + progress_element_id + "' class='attachinary_progress_bar'></div>");
}
$(div).append('<div id="' + attachinary_container_id + '"></div>');

// FIXME: refactor to a separated AttachmentView or similar
// must run the plugin after the element is available in the DOM, not before, hence, the setTimeout
const $storyAttachments = $('<div class="story-attachments"></div>');
$(div).append($storyAttachments);

clearTimeout(window.executeAttachinaryTimeout);
window.executeAttachinaryTimeout = setTimeout(executeAttachinary, 1000);
})
Expand Down Expand Up @@ -477,6 +466,7 @@ module.exports = FormView.extend({
isNew={this.model.isNew()}
editingDescription={this.model.get('editingDescription')}
value={this.model.get("description")}
fileuploadprogressall={this.uploadProgressBar}
onChange={ (event) => this.onChangeModel(event.target.value, "description") }
onClick={this.editDescription}
/>,
Expand All @@ -499,6 +489,18 @@ module.exports = FormView.extend({
);
}

const attachments = this.$('.story-attachments')[0];
if(attachments) {
ReactDOM.render(
<StoryAttachment
name='attachments'
isReadonly={this.isReadonly()}
filesModel={this.model.get('documents')}
/>,
attachments
);
}

this.renderSelects();
this.renderTasks();
this.renderNotes();
Expand Down

0 comments on commit f47b592

Please sign in to comment.