attache_rails 0.2.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 07bb6c168bed2d516774523756dd125d86ca0729
4
- data.tar.gz: b788a5d74a9b1d51c7c6981a6f57d98da62ba060
3
+ metadata.gz: 4da5e22bb598e1b06cbb35fc8492b02f3e004978
4
+ data.tar.gz: 7b1d38f4fb5193ca9490ab1d4463d74938c5300d
5
5
  SHA512:
6
- metadata.gz: 3c8e22d8e34a7a2464af773442eee64f857ccb274e3ea53f9f58732f422b583c2d3b0cca7b32778d5f1d1f407cd166729f68381eff3401358e296bd169d9b65d
7
- data.tar.gz: 1bb4fc71ecfbfa8301ed12eba825dd541ae508b184ebdf62e2c4948033463a025711af00feccde92478e5ae69aca32cee370915dd9535c27bb85a06233546a73
6
+ metadata.gz: b254f432f52a43161cf4c19aed219623e795315984d2fbafa66c09169b39075300776b2a20f8c21bac0465ad130939ec6e7ab2c211e5aa9b772bc1468072b8c3
7
+ data.tar.gz: ed680e0629577892f63c29e103743ba1383e61e6d33427420352f07605e4b8a0425b871c85f36a9210e5cb763dac8925ab1f7e5ff544724fbc318fd39443b12f
@@ -11,8 +11,11 @@ if (typeof AttacheFilePreview === 'undefined') {
11
11
  },
12
12
 
13
13
  render: function() {
14
+ var previewClassName = "attache-file-preview";
15
+
14
16
  // progressbar
15
17
  if (this.state.srcWas != this.props.src) {
18
+ previewClassName = previewClassName + " attache-loading";
16
19
  var className = this.props.className || "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
17
20
  var pctString = this.props.pctString || (this.props.src ? 100 : this.props.percentLoaded) + "%";
18
21
  var pctDesc = this.props.pctDesc || (this.props.src ? 'Loading...' : pctString);
@@ -33,7 +36,7 @@ if (typeof AttacheFilePreview === 'undefined') {
33
36
 
34
37
  // combined
35
38
  return (
36
- React.createElement("div", {className: "attache-file-preview"},
39
+ React.createElement("div", {className: previewClassName},
37
40
  progress,
38
41
  img,
39
42
  React.createElement("div", {className: "clearfix"},
@@ -11,8 +11,11 @@ if (typeof AttacheFilePreview === 'undefined') {
11
11
  },
12
12
 
13
13
  render: function() {
14
+ var previewClassName = "attache-file-preview";
15
+
14
16
  // progressbar
15
17
  if (this.state.srcWas != this.props.src) {
18
+ previewClassName = previewClassName + " attache-loading";
16
19
  var className = this.props.className || "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
17
20
  var pctString = this.props.pctString || (this.props.src ? 100 : this.props.percentLoaded) + "%";
18
21
  var pctDesc = this.props.pctDesc || (this.props.src ? 'Loading...' : pctString);
@@ -33,7 +36,7 @@ if (typeof AttacheFilePreview === 'undefined') {
33
36
 
34
37
  // combined
35
38
  return (
36
- <div className="attache-file-preview">
39
+ <div className={previewClassName}>
37
40
  {progress}
38
41
  {img}
39
42
  <div className="clearfix">
@@ -4,17 +4,18 @@ var AttacheCORSUpload = (function() {
4
4
  AttacheCORSUpload.prototype.onComplete = function(uid, json) { };
5
5
  AttacheCORSUpload.prototype.onProgress = function(uid, json) { };
6
6
  AttacheCORSUpload.prototype.onError = function(uid, status) { alert(status); };
7
+ AttacheCORSUpload.prototype.createLocalThumbnail = function() { }; // for overwriting
7
8
 
8
9
  function AttacheCORSUpload(options) {
9
10
  if (options == null) options = {};
10
11
  for (option in options) {
11
12
  this[option] = options[option];
12
13
  }
13
- this.handleFileSelect(options.file_element);
14
+ this.handleFileSelect(options.file_element, options.files);
14
15
  }
15
16
 
16
- AttacheCORSUpload.prototype.handleFileSelect = function(file_element) {
17
- var f, files, output, _i, _len, _results, url, $ele, prefix;
17
+ AttacheCORSUpload.prototype.handleFileSelect = function(file_element, files) {
18
+ var f, output, _i, _len, _results, url, $ele, prefix;
18
19
  $ele = $(file_element);
19
20
  url = $ele.data('uploadurl');
20
21
  if ($ele.data('hmac')) {
@@ -26,13 +27,13 @@ var AttacheCORSUpload = (function() {
26
27
  }
27
28
 
28
29
  prefix = Date.now() + "_";
29
- files = file_element.files;
30
30
  output = [];
31
31
  _results = [];
32
32
  for (_i = 0, _len = files.length; _i < _len; _i++) {
33
33
  f = files[_i];
34
+ this.createLocalThumbnail(f); // if any
34
35
  f.uid = prefix + (counter++);
35
- this.onProgress(f.uid, { filename: f.name, percentLoaded: 0, bytesLoaded: 0, bytesTotal: f.size });
36
+ this.onProgress(f.uid, { src: f.src, filename: f.name, percentLoaded: 0, bytesLoaded: 0, bytesTotal: f.size });
36
37
  _results.push(this.performUpload(f, url));
37
38
  }
38
39
  return _results;
@@ -74,7 +75,7 @@ var AttacheCORSUpload = (function() {
74
75
  var percentLoaded;
75
76
  if (e.lengthComputable) {
76
77
  percentLoaded = Math.round((e.loaded / e.total) * 100);
77
- return this_s3upload.onProgress(file.uid, { filename: file.name, percentLoaded: percentLoaded, bytesLoaded: e.loaded, bytesTotal: e.total });
78
+ return this_s3upload.onProgress(file.uid, { src: file.src, filename: file.name, percentLoaded: percentLoaded, bytesLoaded: e.loaded, bytesTotal: e.total });
78
79
  }
79
80
  };
80
81
  }
@@ -21,17 +21,20 @@ var AttacheFileInput = React.createClass({displayName: "AttacheFileInput",
21
21
  this.setState(this.state);
22
22
  },
23
23
 
24
- onChange: function() {
25
- var file_element = this.getDOMNode().firstChild;
24
+ performUpload: function(file_element, files) {
26
25
  // user cancelled file chooser dialog. ignore
27
- if (! file_element || file_element.files.length == 0) return;
28
- if (! this.props.multiple) this.state.files = {};
26
+ if (! files || files.length == 0) return;
27
+ if (! this.props.multiple) {
28
+ this.state.files = {};
29
+ files = Array.prototype.splice.apply(files, [0, 1]); // array of 1 element
30
+ }
29
31
 
30
32
  this.setState(this.state);
31
33
  // upload the file via CORS
32
34
  var that = this;
33
35
  new AttacheCORSUpload({
34
36
  file_element: file_element,
37
+ files: files,
35
38
  onComplete: this.setFileValue,
36
39
  onProgress: this.setFileValue,
37
40
  onError: function(uid, status) {
@@ -44,6 +47,31 @@ var AttacheFileInput = React.createClass({displayName: "AttacheFileInput",
44
47
  file_element.value = '';
45
48
  },
46
49
 
50
+ onChange: function() {
51
+ var file_element = this.getDOMNode().firstChild;
52
+ this.performUpload(file_element, file_element && file_element.files);
53
+ },
54
+
55
+ onDragOver: function(e) {
56
+ e.stopPropagation();
57
+ e.preventDefault();
58
+ $(this.getDOMNode()).addClass('attache-dragover');
59
+ },
60
+
61
+ onDragLeave: function(e) {
62
+ e.stopPropagation();
63
+ e.preventDefault();
64
+ $(this.getDOMNode()).removeClass('attache-dragover');
65
+ },
66
+
67
+ onDrop: function(e) {
68
+ e.stopPropagation();
69
+ e.preventDefault();
70
+ var file_element = this.getDOMNode().firstChild;
71
+ this.performUpload(file_element, e.target.files || e.dataTransfer.files);
72
+ $(this.getDOMNode()).removeClass('attache-dragover');
73
+ },
74
+
47
75
  setFileValue: function(key, value) {
48
76
  this.state.files[key] = value;
49
77
  this.setState(this.state);
@@ -58,14 +86,19 @@ var AttacheFileInput = React.createClass({displayName: "AttacheFileInput",
58
86
 
59
87
  var previews = [];
60
88
  $.each(that.state.files, function(key, result) {
89
+ // json is input[value], drop non essential values
90
+ var copy = JSON.parse(JSON.stringify(result));
91
+ delete copy.src;
92
+ delete copy.filename;
93
+ var json = JSON.stringify(copy);
94
+ //
95
+ result.multiple = that.props.multiple;
61
96
  if (result.path) {
62
97
  var parts = result.path.split('/');
63
98
  parts.splice(parts.length-1, 0, encodeURIComponent(that.props['data-geometry'] || '128x128#'));
64
99
  result.src = that.props['data-downloadurl'] + '/' + parts.join('/');
65
100
  result.filename = result.src.split('/').pop().split(/[#?]/).shift();
66
- result.multiple = that.props.multiple;
67
101
  }
68
- var json = JSON.stringify(result);
69
102
  previews.push(
70
103
  React.createElement("div", {className: "attache-file-input"},
71
104
  React.createElement("input", {type: "hidden", name: that.props.name, value: json, readOnly: "true"}),
@@ -90,7 +123,7 @@ var AttacheFileInput = React.createClass({displayName: "AttacheFileInput",
90
123
 
91
124
  var className = ["attache-file-selector", "attache-placeholders-count-" + placeholders.length, "attache-previews-count-" + previews.length, this.props['data-classname']].join(' ').trim();
92
125
  return (
93
- React.createElement("label", {htmlFor: that.props.id, className: className},
126
+ React.createElement("label", {htmlFor: that.props.id, className: className, onDragOver: this.onDragOver, onDragLeave: this.onDragLeave, onDrop: this.onDrop},
94
127
  React.createElement("input", React.__spread({type: "file"}, that.props, {onChange: this.onChange})),
95
128
  React.createElement("input", {type: "hidden", name: that.props.name, value: ""}),
96
129
  React.createElement(Header, React.__spread({}, that.props)),
@@ -21,17 +21,20 @@ var AttacheFileInput = React.createClass({
21
21
  this.setState(this.state);
22
22
  },
23
23
 
24
- onChange: function() {
25
- var file_element = this.getDOMNode().firstChild;
24
+ performUpload: function(file_element, files) {
26
25
  // user cancelled file chooser dialog. ignore
27
- if (! file_element || file_element.files.length == 0) return;
28
- if (! this.props.multiple) this.state.files = {};
26
+ if (! files || files.length == 0) return;
27
+ if (! this.props.multiple) {
28
+ this.state.files = {};
29
+ files = Array.prototype.splice.apply(files, [0, 1]); // array of 1 element
30
+ }
29
31
 
30
32
  this.setState(this.state);
31
33
  // upload the file via CORS
32
34
  var that = this;
33
35
  new AttacheCORSUpload({
34
36
  file_element: file_element,
37
+ files: files,
35
38
  onComplete: this.setFileValue,
36
39
  onProgress: this.setFileValue,
37
40
  onError: function(uid, status) {
@@ -44,6 +47,31 @@ var AttacheFileInput = React.createClass({
44
47
  file_element.value = '';
45
48
  },
46
49
 
50
+ onChange: function() {
51
+ var file_element = this.getDOMNode().firstChild;
52
+ this.performUpload(file_element, file_element && file_element.files);
53
+ },
54
+
55
+ onDragOver: function(e) {
56
+ e.stopPropagation();
57
+ e.preventDefault();
58
+ $(this.getDOMNode()).addClass('attache-dragover');
59
+ },
60
+
61
+ onDragLeave: function(e) {
62
+ e.stopPropagation();
63
+ e.preventDefault();
64
+ $(this.getDOMNode()).removeClass('attache-dragover');
65
+ },
66
+
67
+ onDrop: function(e) {
68
+ e.stopPropagation();
69
+ e.preventDefault();
70
+ var file_element = this.getDOMNode().firstChild;
71
+ this.performUpload(file_element, e.target.files || e.dataTransfer.files);
72
+ $(this.getDOMNode()).removeClass('attache-dragover');
73
+ },
74
+
47
75
  setFileValue: function(key, value) {
48
76
  this.state.files[key] = value;
49
77
  this.setState(this.state);
@@ -58,14 +86,19 @@ var AttacheFileInput = React.createClass({
58
86
 
59
87
  var previews = [];
60
88
  $.each(that.state.files, function(key, result) {
89
+ // json is input[value], drop non essential values
90
+ var copy = JSON.parse(JSON.stringify(result));
91
+ delete copy.src;
92
+ delete copy.filename;
93
+ var json = JSON.stringify(copy);
94
+ //
95
+ result.multiple = that.props.multiple;
61
96
  if (result.path) {
62
97
  var parts = result.path.split('/');
63
98
  parts.splice(parts.length-1, 0, encodeURIComponent(that.props['data-geometry'] || '128x128#'));
64
99
  result.src = that.props['data-downloadurl'] + '/' + parts.join('/');
65
100
  result.filename = result.src.split('/').pop().split(/[#?]/).shift();
66
- result.multiple = that.props.multiple;
67
101
  }
68
- var json = JSON.stringify(result);
69
102
  previews.push(
70
103
  <div className="attache-file-input">
71
104
  <input type="hidden" name={that.props.name} value={json} readOnly="true" />
@@ -90,7 +123,7 @@ var AttacheFileInput = React.createClass({
90
123
 
91
124
  var className = ["attache-file-selector", "attache-placeholders-count-" + placeholders.length, "attache-previews-count-" + previews.length, this.props['data-classname']].join(' ').trim();
92
125
  return (
93
- <label htmlFor={that.props.id} className={className}>
126
+ <label htmlFor={that.props.id} className={className} onDragOver={this.onDragOver} onDragLeave={this.onDragLeave} onDrop={this.onDrop}>
94
127
  <input type="file" {...that.props} onChange={this.onChange}/>
95
128
  <input type="hidden" name={that.props.name} value="" />
96
129
  <Header {...that.props} />
@@ -92,7 +92,8 @@ module AttacheRails
92
92
  define_method "#{name}_attributes", -> (geometry) { str = self.send(name); Utils.attache_url_for(str, geometry) if str; }
93
93
  define_method "#{name}=", -> (value) {
94
94
  new_value = (value.respond_to?(:read) ? Utils.attache_upload_and_get_json(value) : value)
95
- super(Utils.array(new_value).first)
95
+ okay = JSON.parse(new_value)['path'] rescue nil
96
+ super(Utils.array(okay ? new_value : nil).first)
96
97
  }
97
98
  define_method "#{name}_discard_was",-> do
98
99
  new_value = self.send("#{name}")
@@ -121,7 +122,11 @@ module AttacheRails
121
122
  end
122
123
  }
123
124
  define_method "#{name}=", -> (array) {
124
- new_value = Utils.array(array).collect {|value| value.respond_to?(:read) ? Utils.attache_upload_and_get_json(value) : value }
125
+ new_value = Utils.array(array).inject([]) {|sum,value|
126
+ hash = value.respond_to?(:read) ? Utils.attache_upload_and_get_json(value) : value
127
+ okay = JSON.parse(hash)['path'] rescue nil
128
+ okay ? sum + [hash] : sum
129
+ }
125
130
  super(Utils.array new_value)
126
131
  }
127
132
  define_method "#{name}_discard_was",-> do
@@ -1,3 +1,3 @@
1
1
  module AttacheRails
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
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.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - choonkeat
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-04 00:00:00.000000000 Z
11
+ date: 2015-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails