attache_rails 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -2
- data/app/assets/javascripts/attache/bootstrap3.js +40 -98
- data/app/assets/javascripts/attache/bootstrap3.js.jsx +40 -98
- data/app/assets/javascripts/attache/cors_upload.js +9 -9
- data/app/assets/javascripts/attache/file_input.js +71 -0
- data/app/assets/javascripts/attache/file_input.js.jsx +71 -0
- data/app/assets/javascripts/attache.js +1 -0
- data/lib/attache_rails/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: edd291b58ed01055cda499254592cfd028ed2cde
|
4
|
+
data.tar.gz: e8c95574587c899c798cb3fe550523a86222ffa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6b5fa2be93e5a90b22bd39e58330eeaf663733af892a0c98ddd7c76fa2500ba8d3b6805b10a33dd1ffaddaf1f7c4b81654991845991b5e151f14e6f5b31a937
|
7
|
+
data.tar.gz: 9889e52f28712d7c5a10a50933ec7d637cb45a111b51fbcd92620989dfe883e88a71d1a464910b67a4068be658dcbe63b765ab8feabb6393035993ad02e6f942
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Ruby on Rails integration for [attache server](https://github.com/choonkeat/attache)
|
4
4
|
|
5
|
-
NOTE: You can learn how to use this gem by looking at the [changes made to our example app](https://github.com/choonkeat/attache-railsapp/
|
5
|
+
NOTE: You can learn how to use this gem by looking at the [changes made to our example app](https://github.com/choonkeat/attache-railsapp/compare/fc47c17...master) or follow the step by step instructions in this `README`
|
6
6
|
|
7
7
|
## Dependencies
|
8
8
|
|
@@ -32,10 +32,19 @@ Or you can include the various scripts yourself
|
|
32
32
|
|
33
33
|
``` javascript
|
34
34
|
//= require attache/cors_upload
|
35
|
+
//= require attache/file_input
|
35
36
|
//= require attache/bootstrap3
|
36
37
|
//= require attache/ujs
|
37
38
|
```
|
38
39
|
|
40
|
+
If you want to customize the file upload look and feel, define your own react `<AttacheFilePreview/>` renderer *before* including the attache js. For example,
|
41
|
+
|
42
|
+
``` javascript
|
43
|
+
//= require ./my_attache_file_preview.js
|
44
|
+
//= require attache
|
45
|
+
```
|
46
|
+
|
47
|
+
|
39
48
|
## Usage
|
40
49
|
|
41
50
|
### Database
|
@@ -138,7 +147,6 @@ Alternatively, you can get the list of urls and manipulate it however you want
|
|
138
147
|
* If this variable is not set, then upload requests will not be signed & `ATTACHE_UPLOAD_DURATION` will be ignored
|
139
148
|
* If this variable is set, it must be the same value as `SECRET_KEY` is set on the `attache` server
|
140
149
|
|
141
|
-
|
142
150
|
# License
|
143
151
|
|
144
152
|
MIT
|
@@ -1,106 +1,48 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
new CORSUpload({
|
28
|
-
file_element: file_element, onComplete: this.setFileValue, onProgress: this.setFileValue,
|
29
|
-
onError: function(uid, status) { that.setFileValue(uid, { pctString: '90%', pctDesc: status, className: 'progress-bar progress-bar-danger' }); }
|
30
|
-
});
|
31
|
-
// we don't want the file binary to be uploaded in the main form
|
32
|
-
file_element.value = '';
|
33
|
-
},
|
34
|
-
|
35
|
-
setFileValue: function(key, value) {
|
36
|
-
this.state.files[key] = value;
|
37
|
-
this.setState(this.state);
|
38
|
-
},
|
39
|
-
|
40
|
-
render: function() {
|
41
|
-
var that = this;
|
42
|
-
var previews = [];
|
43
|
-
$.each(that.state.files, function(key, result) {
|
44
|
-
var json = JSON.stringify(result);
|
45
|
-
if (result.path) {
|
46
|
-
var parts = result.path.split('/');
|
47
|
-
parts.splice(parts.length-1, 0, encodeURIComponent(that.props['data-geometry'] || '128x128#'));
|
48
|
-
result.src = that.props['data-downloadurl'] + '/' + parts.join('/');
|
1
|
+
if (typeof AttacheFilePreview === 'undefined') {
|
2
|
+
|
3
|
+
var AttacheFilePreview = React.createClass({displayName: "AttacheFilePreview",
|
4
|
+
|
5
|
+
getInitialState: function() {
|
6
|
+
return { srcWas: '' };
|
7
|
+
},
|
8
|
+
|
9
|
+
onSrcLoaded: function() {
|
10
|
+
this.setState({ srcWas: this.props.src });
|
11
|
+
},
|
12
|
+
|
13
|
+
render: function() {
|
14
|
+
// progressbar
|
15
|
+
if (this.state.srcWas != this.props.src) {
|
16
|
+
var className = this.props.className || "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
|
17
|
+
var pctString = this.props.pctString || (this.props.src ? 100 : this.props.percentLoaded) + "%";
|
18
|
+
var pctDesc = this.props.pctDesc || (this.props.src ? 'Loading...' : pctString);
|
19
|
+
var pctStyle = { width: pctString, minWidth: '3em' };
|
20
|
+
var progress = (
|
21
|
+
React.createElement("div", {className: "progress"},
|
22
|
+
React.createElement("div", {className: className, role: "progressbar", "aria-valuenow": this.props.percentLoaded, "aria-valuemin": "0", "aria-valuemax": "100", style: pctStyle},
|
23
|
+
pctDesc
|
24
|
+
)
|
25
|
+
)
|
26
|
+
);
|
49
27
|
}
|
50
|
-
previews.push(
|
51
|
-
React.createElement("div", {className: "thumbnail"},
|
52
|
-
React.createElement("input", {type: "hidden", name: that.props.name, value: result.path, readOnly: "true"}),
|
53
|
-
React.createElement(AttacheFilePreview, React.__spread({}, result, {key: key, onRemove: that.onRemove.bind(that, key)}))
|
54
|
-
)
|
55
|
-
);
|
56
|
-
});
|
57
|
-
return (
|
58
|
-
React.createElement("label", {htmlFor: this.props.id, className: "attache-file-selector"},
|
59
|
-
React.createElement("input", React.__spread({type: "file"}, this.props, {onChange: this.onChange})),
|
60
|
-
previews
|
61
|
-
)
|
62
|
-
);
|
63
|
-
}
|
64
|
-
});
|
65
|
-
|
66
|
-
var AttacheFilePreview = React.createClass({displayName: "AttacheFilePreview",
|
67
|
-
|
68
|
-
getInitialState: function() {
|
69
|
-
return { srcWas: '' };
|
70
|
-
},
|
71
28
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
render: function() {
|
77
|
-
var className = this.props.className || "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
|
78
|
-
var pctString = this.props.pctString || (this.props.src ? 100 : this.props.percentLoaded) + "%";
|
79
|
-
var pctDesc = this.props.pctDesc || (this.props.src ? 'Loading...' : pctString);
|
80
|
-
var img = (this.props.src ? (React.createElement("img", {src: this.props.src, onLoad: this.removeProgressBar})) : '');
|
81
|
-
var pctStyle = { width: pctString, minWidth: '3em' };
|
82
|
-
var cptStyle = { textOverflow: "ellipsis" };
|
83
|
-
var caption = React.createElement("div", {className: "pull-left", style: cptStyle}, this.props.filename || this.props.path && this.props.path.split('/').pop());
|
29
|
+
// img tag
|
30
|
+
if (this.props.src) {
|
31
|
+
var img = React.createElement("img", {src: this.props.src, onLoad: this.onSrcLoaded});
|
32
|
+
}
|
84
33
|
|
85
|
-
|
86
|
-
|
87
|
-
React.createElement("div", {className: "
|
88
|
-
|
89
|
-
|
34
|
+
// combined
|
35
|
+
return (
|
36
|
+
React.createElement("div", {className: "attache-file-preview"},
|
37
|
+
progress,
|
38
|
+
img,
|
39
|
+
React.createElement("div", {className: "clearfix"},
|
40
|
+
React.createElement("div", {className: "pull-left", style: "textOverflow: 'ellipsis;'"}, this.props.filename),
|
41
|
+
React.createElement("a", {href: "#remove", className: "pull-right", onClick: this.props.onRemove, title: "Click to remove"}, "×")
|
90
42
|
)
|
91
43
|
)
|
92
44
|
);
|
93
45
|
}
|
46
|
+
});
|
94
47
|
|
95
|
-
|
96
|
-
React.createElement("div", {className: "attache-file-preview"},
|
97
|
-
progress,
|
98
|
-
img,
|
99
|
-
React.createElement("div", {className: "clearfix"},
|
100
|
-
caption,
|
101
|
-
React.createElement("a", {href: "#remove", className: "pull-right", onClick: this.props.onRemove, title: "Click to remove"}, "×")
|
102
|
-
)
|
103
|
-
)
|
104
|
-
);
|
105
|
-
}
|
106
|
-
});
|
48
|
+
}
|
@@ -1,106 +1,48 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
new CORSUpload({
|
28
|
-
file_element: file_element, onComplete: this.setFileValue, onProgress: this.setFileValue,
|
29
|
-
onError: function(uid, status) { that.setFileValue(uid, { pctString: '90%', pctDesc: status, className: 'progress-bar progress-bar-danger' }); }
|
30
|
-
});
|
31
|
-
// we don't want the file binary to be uploaded in the main form
|
32
|
-
file_element.value = '';
|
33
|
-
},
|
34
|
-
|
35
|
-
setFileValue: function(key, value) {
|
36
|
-
this.state.files[key] = value;
|
37
|
-
this.setState(this.state);
|
38
|
-
},
|
39
|
-
|
40
|
-
render: function() {
|
41
|
-
var that = this;
|
42
|
-
var previews = [];
|
43
|
-
$.each(that.state.files, function(key, result) {
|
44
|
-
var json = JSON.stringify(result);
|
45
|
-
if (result.path) {
|
46
|
-
var parts = result.path.split('/');
|
47
|
-
parts.splice(parts.length-1, 0, encodeURIComponent(that.props['data-geometry'] || '128x128#'));
|
48
|
-
result.src = that.props['data-downloadurl'] + '/' + parts.join('/');
|
1
|
+
if (typeof AttacheFilePreview === 'undefined') {
|
2
|
+
|
3
|
+
var AttacheFilePreview = React.createClass({
|
4
|
+
|
5
|
+
getInitialState: function() {
|
6
|
+
return { srcWas: '' };
|
7
|
+
},
|
8
|
+
|
9
|
+
onSrcLoaded: function() {
|
10
|
+
this.setState({ srcWas: this.props.src });
|
11
|
+
},
|
12
|
+
|
13
|
+
render: function() {
|
14
|
+
// progressbar
|
15
|
+
if (this.state.srcWas != this.props.src) {
|
16
|
+
var className = this.props.className || "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
|
17
|
+
var pctString = this.props.pctString || (this.props.src ? 100 : this.props.percentLoaded) + "%";
|
18
|
+
var pctDesc = this.props.pctDesc || (this.props.src ? 'Loading...' : pctString);
|
19
|
+
var pctStyle = { width: pctString, minWidth: '3em' };
|
20
|
+
var progress = (
|
21
|
+
<div className="progress">
|
22
|
+
<div className={className} role="progressbar" aria-valuenow={this.props.percentLoaded} aria-valuemin="0" aria-valuemax="100" style={pctStyle}>
|
23
|
+
{pctDesc}
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
);
|
49
27
|
}
|
50
|
-
previews.push(
|
51
|
-
<div className="thumbnail">
|
52
|
-
<input type="hidden" name={that.props.name} value={result.path} readOnly="true" />
|
53
|
-
<AttacheFilePreview {...result} key={key} onRemove={that.onRemove.bind(that, key)}/>
|
54
|
-
</div>
|
55
|
-
);
|
56
|
-
});
|
57
|
-
return (
|
58
|
-
<label htmlFor={this.props.id} className="attache-file-selector">
|
59
|
-
<input type="file" {...this.props} onChange={this.onChange}/>
|
60
|
-
{previews}
|
61
|
-
</label>
|
62
|
-
);
|
63
|
-
}
|
64
|
-
});
|
65
|
-
|
66
|
-
var AttacheFilePreview = React.createClass({
|
67
|
-
|
68
|
-
getInitialState: function() {
|
69
|
-
return { srcWas: '' };
|
70
|
-
},
|
71
28
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
render: function() {
|
77
|
-
var className = this.props.className || "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
|
78
|
-
var pctString = this.props.pctString || (this.props.src ? 100 : this.props.percentLoaded) + "%";
|
79
|
-
var pctDesc = this.props.pctDesc || (this.props.src ? 'Loading...' : pctString);
|
80
|
-
var img = (this.props.src ? (<img src={this.props.src} onLoad={this.removeProgressBar} />) : '');
|
81
|
-
var pctStyle = { width: pctString, minWidth: '3em' };
|
82
|
-
var cptStyle = { textOverflow: "ellipsis" };
|
83
|
-
var caption = <div className="pull-left" style={cptStyle}>{this.props.filename || this.props.path && this.props.path.split('/').pop()}</div>;
|
29
|
+
// img tag
|
30
|
+
if (this.props.src) {
|
31
|
+
var img = <img src={this.props.src} onLoad={this.onSrcLoaded} />;
|
32
|
+
}
|
84
33
|
|
85
|
-
|
86
|
-
|
87
|
-
<div className="
|
88
|
-
|
89
|
-
|
34
|
+
// combined
|
35
|
+
return (
|
36
|
+
<div className="attache-file-preview">
|
37
|
+
{progress}
|
38
|
+
{img}
|
39
|
+
<div className="clearfix">
|
40
|
+
<div className="pull-left" style="textOverflow: 'ellipsis;'">{this.props.filename}</div>
|
41
|
+
<a href="#remove" className="pull-right" onClick={this.props.onRemove} title="Click to remove">×</a>
|
90
42
|
</div>
|
91
43
|
</div>
|
92
44
|
);
|
93
45
|
}
|
46
|
+
});
|
94
47
|
|
95
|
-
|
96
|
-
<div className="attache-file-preview">
|
97
|
-
{progress}
|
98
|
-
{img}
|
99
|
-
<div className="clearfix">
|
100
|
-
{caption}
|
101
|
-
<a href="#remove" className="pull-right" onClick={this.props.onRemove} title="Click to remove">×</a>
|
102
|
-
</div>
|
103
|
-
</div>
|
104
|
-
);
|
105
|
-
}
|
106
|
-
});
|
48
|
+
}
|
@@ -1,11 +1,11 @@
|
|
1
|
-
var
|
1
|
+
var AttacheCORSUpload = (function() {
|
2
2
|
var counter = 0;
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
AttacheCORSUpload.prototype.onComplete = function(uid, json) { };
|
5
|
+
AttacheCORSUpload.prototype.onProgress = function(uid, json) { };
|
6
|
+
AttacheCORSUpload.prototype.onError = function(uid, status) { alert(status); };
|
7
7
|
|
8
|
-
function
|
8
|
+
function AttacheCORSUpload(options) {
|
9
9
|
if (options == null) options = {};
|
10
10
|
for (option in options) {
|
11
11
|
this[option] = options[option];
|
@@ -13,7 +13,7 @@ var CORSUpload = (function() {
|
|
13
13
|
this.handleFileSelect(options.file_element);
|
14
14
|
}
|
15
15
|
|
16
|
-
|
16
|
+
AttacheCORSUpload.prototype.handleFileSelect = function(file_element) {
|
17
17
|
var f, files, output, _i, _len, _results, url, $ele;
|
18
18
|
$ele = $(file_element);
|
19
19
|
url = $ele.data('uploadurl');
|
@@ -37,7 +37,7 @@ var CORSUpload = (function() {
|
|
37
37
|
return _results;
|
38
38
|
};
|
39
39
|
|
40
|
-
|
40
|
+
AttacheCORSUpload.prototype.createCORSRequest = function(method, url) {
|
41
41
|
var xhr;
|
42
42
|
xhr = new XMLHttpRequest();
|
43
43
|
if (xhr.withCredentials != null) {
|
@@ -51,7 +51,7 @@ var CORSUpload = (function() {
|
|
51
51
|
return xhr;
|
52
52
|
};
|
53
53
|
|
54
|
-
|
54
|
+
AttacheCORSUpload.prototype.performUpload = function(file, url) {
|
55
55
|
var this_s3upload, xhr;
|
56
56
|
this_s3upload = this;
|
57
57
|
url = url + (url.indexOf('?') == -1 ? '?' : '&') + 'file=' + encodeURIComponent(file.name);
|
@@ -80,6 +80,6 @@ var CORSUpload = (function() {
|
|
80
80
|
return xhr.send(file);
|
81
81
|
};
|
82
82
|
|
83
|
-
return
|
83
|
+
return AttacheCORSUpload;
|
84
84
|
|
85
85
|
})();
|
@@ -0,0 +1,71 @@
|
|
1
|
+
var AttacheFileInput = React.createClass({displayName: "AttacheFileInput",
|
2
|
+
|
3
|
+
getInitialState: function() {
|
4
|
+
var files = {};
|
5
|
+
var array = ([].concat(JSON.parse(this.props['data-value'])));
|
6
|
+
$.each(array, function(uid, json) {
|
7
|
+
if (json) files[uid] = { path: json };
|
8
|
+
});
|
9
|
+
return {files: files};
|
10
|
+
},
|
11
|
+
|
12
|
+
onRemove: function(uid, e) {
|
13
|
+
delete this.state.files[uid];
|
14
|
+
this.setState(this.state);
|
15
|
+
e.preventDefault();
|
16
|
+
e.stopPropagation();
|
17
|
+
},
|
18
|
+
|
19
|
+
onChange: function() {
|
20
|
+
var file_element = this.getDOMNode().firstChild;
|
21
|
+
// user cancelled file chooser dialog. ignore
|
22
|
+
if (file_element.files.length == 0) return;
|
23
|
+
this.state.files = {};
|
24
|
+
this.setState(this.state);
|
25
|
+
// upload the file via CORS
|
26
|
+
var that = this;
|
27
|
+
new AttacheCORSUpload({
|
28
|
+
file_element: file_element,
|
29
|
+
onComplete: this.setFileValue,
|
30
|
+
onProgress: this.setFileValue,
|
31
|
+
onError: function(uid, status) {
|
32
|
+
that.setFileValue(uid, { pctString: '90%', pctDesc: status, className: 'progress-bar progress-bar-danger' });
|
33
|
+
}
|
34
|
+
});
|
35
|
+
|
36
|
+
// we don't want the file binary to be uploaded in the main form
|
37
|
+
// so the actual file input is neutered
|
38
|
+
file_element.value = '';
|
39
|
+
},
|
40
|
+
|
41
|
+
setFileValue: function(key, value) {
|
42
|
+
this.state.files[key] = value;
|
43
|
+
this.setState(this.state);
|
44
|
+
},
|
45
|
+
|
46
|
+
render: function() {
|
47
|
+
var that = this;
|
48
|
+
var previews = [];
|
49
|
+
$.each(that.state.files, function(key, result) {
|
50
|
+
var json = JSON.stringify(result);
|
51
|
+
if (result.path) {
|
52
|
+
var parts = result.path.split('/');
|
53
|
+
parts.splice(parts.length-1, 0, encodeURIComponent(that.props['data-geometry'] || '128x128#'));
|
54
|
+
result.src = that.props['data-downloadurl'] + '/' + parts.join('/');
|
55
|
+
result.filename = result.src.split('/').pop().split(/[#?]/).shift();
|
56
|
+
}
|
57
|
+
previews.push(
|
58
|
+
React.createElement("div", {className: "attache-file-input"},
|
59
|
+
React.createElement("input", {type: "hidden", name: that.props.name, value: result.path, readOnly: "true"}),
|
60
|
+
React.createElement(AttacheFilePreview, React.__spread({}, result, {key: key, onRemove: that.onRemove.bind(that, key)}))
|
61
|
+
)
|
62
|
+
);
|
63
|
+
});
|
64
|
+
return (
|
65
|
+
React.createElement("label", {htmlFor: this.props.id, className: "attache-file-selector"},
|
66
|
+
React.createElement("input", React.__spread({type: "file"}, this.props, {onChange: this.onChange})),
|
67
|
+
previews
|
68
|
+
)
|
69
|
+
);
|
70
|
+
}
|
71
|
+
});
|
@@ -0,0 +1,71 @@
|
|
1
|
+
var AttacheFileInput = React.createClass({
|
2
|
+
|
3
|
+
getInitialState: function() {
|
4
|
+
var files = {};
|
5
|
+
var array = ([].concat(JSON.parse(this.props['data-value'])));
|
6
|
+
$.each(array, function(uid, json) {
|
7
|
+
if (json) files[uid] = { path: json };
|
8
|
+
});
|
9
|
+
return {files: files};
|
10
|
+
},
|
11
|
+
|
12
|
+
onRemove: function(uid, e) {
|
13
|
+
delete this.state.files[uid];
|
14
|
+
this.setState(this.state);
|
15
|
+
e.preventDefault();
|
16
|
+
e.stopPropagation();
|
17
|
+
},
|
18
|
+
|
19
|
+
onChange: function() {
|
20
|
+
var file_element = this.getDOMNode().firstChild;
|
21
|
+
// user cancelled file chooser dialog. ignore
|
22
|
+
if (file_element.files.length == 0) return;
|
23
|
+
this.state.files = {};
|
24
|
+
this.setState(this.state);
|
25
|
+
// upload the file via CORS
|
26
|
+
var that = this;
|
27
|
+
new AttacheCORSUpload({
|
28
|
+
file_element: file_element,
|
29
|
+
onComplete: this.setFileValue,
|
30
|
+
onProgress: this.setFileValue,
|
31
|
+
onError: function(uid, status) {
|
32
|
+
that.setFileValue(uid, { pctString: '90%', pctDesc: status, className: 'progress-bar progress-bar-danger' });
|
33
|
+
}
|
34
|
+
});
|
35
|
+
|
36
|
+
// we don't want the file binary to be uploaded in the main form
|
37
|
+
// so the actual file input is neutered
|
38
|
+
file_element.value = '';
|
39
|
+
},
|
40
|
+
|
41
|
+
setFileValue: function(key, value) {
|
42
|
+
this.state.files[key] = value;
|
43
|
+
this.setState(this.state);
|
44
|
+
},
|
45
|
+
|
46
|
+
render: function() {
|
47
|
+
var that = this;
|
48
|
+
var previews = [];
|
49
|
+
$.each(that.state.files, function(key, result) {
|
50
|
+
var json = JSON.stringify(result);
|
51
|
+
if (result.path) {
|
52
|
+
var parts = result.path.split('/');
|
53
|
+
parts.splice(parts.length-1, 0, encodeURIComponent(that.props['data-geometry'] || '128x128#'));
|
54
|
+
result.src = that.props['data-downloadurl'] + '/' + parts.join('/');
|
55
|
+
result.filename = result.src.split('/').pop().split(/[#?]/).shift();
|
56
|
+
}
|
57
|
+
previews.push(
|
58
|
+
<div className="attache-file-input">
|
59
|
+
<input type="hidden" name={that.props.name} value={result.path} readOnly="true" />
|
60
|
+
<AttacheFilePreview {...result} key={key} onRemove={that.onRemove.bind(that, key)}/>
|
61
|
+
</div>
|
62
|
+
);
|
63
|
+
});
|
64
|
+
return (
|
65
|
+
<label htmlFor={this.props.id} className="attache-file-selector">
|
66
|
+
<input type="file" {...this.props} onChange={this.onChange}/>
|
67
|
+
{previews}
|
68
|
+
</label>
|
69
|
+
);
|
70
|
+
}
|
71
|
+
});
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attache_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- choonkeat
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -24,6 +24,8 @@ files:
|
|
24
24
|
- app/assets/javascripts/attache/bootstrap3.js
|
25
25
|
- app/assets/javascripts/attache/bootstrap3.js.jsx
|
26
26
|
- app/assets/javascripts/attache/cors_upload.js
|
27
|
+
- app/assets/javascripts/attache/file_input.js
|
28
|
+
- app/assets/javascripts/attache/file_input.js.jsx
|
27
29
|
- app/assets/javascripts/attache/ujs.js
|
28
30
|
- lib/attache_rails.rb
|
29
31
|
- lib/attache_rails/engine.rb
|