uploadbox 0.0.13 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf3cbfed4974a811cdaa9bc00700fdb1cc8d57e0
4
- data.tar.gz: 5f080cd8e8be770faf1ae1310568158ae8884a4f
3
+ metadata.gz: 93240b0280249b35b89cd367932e1b2de5e6cce9
4
+ data.tar.gz: e94a982a1aeb55497b4825a2ff89be06037d2914
5
5
  SHA512:
6
- metadata.gz: bd6b3534fb34c79dd511e3c1fbd12b0865df99e938197d21083dbf44b974218e8d3eb1b8b967d0a48cc9aee992663830796ac4e23701842dbc099331d41838da
7
- data.tar.gz: b03253560ed00d6b9f1c6000912c63c4a2d125acded190bfdec3fa20cc647a66b602f8f912920c942a87b3a84b61e357fa757e0c28be2b50d922b392abec20e3
6
+ metadata.gz: 0c1221c95ae558e91ac8699db2ea603bdfb46b5b85a77aea927b58733ebaa52c66a7a621872ade40572d6f988d08998c8e92f370499d9f50c214b29443447649
7
+ data.tar.gz: 2386b4127cedfc97a72c7ec8133748fddb14ebcbb88f921a73f36bd3218d13f88dfdc6774482631f5aecc9d36e09fb303b899df23bc5ad152d699d68a95383bf
Binary file
@@ -7,6 +7,7 @@
7
7
  <font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
8
8
  <missing-glyph horiz-adv-x="1000" />
9
9
  <glyph glyph-name="picture-1" unicode="&#xe800;" d="m357 529q0-45-31-76t-76-32t-76 32t-31 76t31 75t76 32t76-32t31-75z m572-215v-250h-786v107l178 179l90-89l285 285z m53 393h-893q-7 0-12-5t-6-13v-678q0-8 6-13t12-5h893q7 0 13 5t5 13v678q0 7-5 13t-13 5z m89-18v-678q0-37-26-63t-63-27h-893q-36 0-63 27t-26 63v678q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" />
10
+ <glyph glyph-name="plus-1" unicode="&#xe802;" d="m786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q22 0 38-16t16-38z" horiz-adv-x="785.7" />
10
11
  </font>
11
12
  </defs>
12
13
  </svg>
Binary file
Binary file
@@ -0,0 +1,64 @@
1
+ class @GalleryUploader
2
+ constructor: (@container) ->
3
+ @previews = {}
4
+
5
+ @container.find('input[type="file"]:first').show().fileupload
6
+ type: 'POST'
7
+ dataType: 'xml'
8
+ replaceFileInput: false
9
+ autoUpload: true
10
+ formData: @getFormData
11
+ dropZone: @container
12
+ pasteZone: @container
13
+ add: @add
14
+ progress: @progress
15
+ done: @done
16
+ fail: @fail
17
+
18
+ add: (e, data) =>
19
+ if @loader
20
+ @loader.detach()
21
+
22
+ if @verifyProcessingInterval
23
+ clearInterval(@verifyProcessingInterval)
24
+
25
+ if data.files[0].type.match /gif|jpe?g|png/
26
+ @clone = @container.find('[data-container="uploader"]:first').clone()
27
+ @container.append(@clone)
28
+ previewInstanceName = Manager.getInstanceName('UploaderPreview')
29
+ preview = new UploaderPreview(@clone, data.files[0])
30
+ @clone.data(previewInstanceName, preview)
31
+ @previews[preview.id()] = preview
32
+ data.context = preview.id()
33
+
34
+ @container.closest('form').find('[type=submit]').attr("disabled", true)
35
+ data.submit()
36
+
37
+ getFormData: =>
38
+ preview = @nextPreview()
39
+ filePath = "uploads/#{preview.id()}/" + preview.file.name
40
+ preview.filePath = filePath
41
+ [
42
+ { name: 'key', value: filePath },
43
+ { name: 'acl', value: @container.find('input[name="acl"]').val() },
44
+ { name: 'Content-Type', value: preview.file.type },
45
+ { name: 'AWSAccessKeyId', value: @container.find('input[name="AWSAccessKeyId"]').val() },
46
+ { name: 'policy', value: @container.find('input[name="policy"]').val() },
47
+ { name: 'signature', value: @container.find('input[name="signature"]').val() },
48
+ { name: 'file', value: preview.file }
49
+ ]
50
+
51
+ progress: (e, data) =>
52
+ @previews[data.context].progress(data)
53
+
54
+ done: (e, data) =>
55
+ @previews[data.context].done(data)
56
+
57
+ fail: (e, data) =>
58
+ @previews[data.context].fail(data)
59
+
60
+ nextPreview: =>
61
+ @currentIndex ||= 0
62
+ key = Object.keys(@previews)[@currentIndex]
63
+ @currentIndex++
64
+ @previews[key]
@@ -0,0 +1,18 @@
1
+ class @Manager
2
+ @getInstanceName: (className) ->
3
+ className.charAt(0).toLowerCase() + className.slice(1)
4
+
5
+ @init = (container) ->
6
+ classNames = container.data('component').split(' ')
7
+
8
+ for className in classNames
9
+ try
10
+ instance = new (eval(className))(container)
11
+ instanceName = Manager.getInstanceName(className)
12
+ container.data(instanceName, instance)
13
+ catch error
14
+ try
15
+ console.warn "#{className} component not found"
16
+
17
+ $(document).ready ->
18
+ $('[data-component]').each (i, el) -> Manager.init($(el))
@@ -0,0 +1,134 @@
1
+ class @UploaderPreview
2
+ constructor: (@container, @file) ->
3
+ @loader = $('<div class="progress progress-striped active"><div class="bar" style="width: 0%;"></div></div>').hide()
4
+
5
+ @startLoader() if @isUploadStarting()
6
+
7
+ @container.find('a.btn.fileupload-exists').bind('ajax:success', @delete)
8
+
9
+ @container.find('input[type="file"]:first').show().fileupload
10
+ type: 'POST'
11
+ dataType: 'xml'
12
+ replaceFileInput: false
13
+ autoUpload: true
14
+ formData: @getFormData
15
+ dropZone: @container
16
+ pasteZone: @container
17
+ add: @add
18
+ progress: @progress
19
+ done: @done
20
+ fail: @fail
21
+
22
+ @fileInput = @container.find('input[type="file"]')
23
+ @typeInput = @container.find('input[name="image[imageable_type]"]')
24
+ @uploadNameInput = @container.find('input[name="image[upload_name]"]')
25
+ @idInput = @container.find('[data-item="id"]')
26
+ @thumbContainer = @container.find('.fileupload-preview.thumbnail')
27
+
28
+ startLoader: =>
29
+ @container.prepend(@loader.fadeIn())
30
+ @container.find('.fileupload').removeClass('processing').addClass('uploading')
31
+
32
+
33
+ add: (e, data) =>
34
+ @file = data.files[0]
35
+
36
+ if @loader
37
+ @loader.detach()
38
+
39
+ if @verifyProcessingInterval
40
+ clearInterval(@verifyProcessingInterval)
41
+
42
+ if @file.type.match /gif|jpe?g|png/
43
+ data.context = @id()
44
+ @startLoader()
45
+ @container.closest('form').find('[type=submit]').attr("disabled", true)
46
+ data.submit()
47
+
48
+ getFormData: =>
49
+ @filePath = "uploads/#{@id()}/" + @file.name
50
+
51
+ [
52
+ { name: 'key', value: @filePath },
53
+ { name: 'acl', value: @container.find('input[name="acl"]').val() },
54
+ { name: 'Content-Type', value: @file.type },
55
+ { name: 'AWSAccessKeyId', value: @container.find('input[name="AWSAccessKeyId"]').val() },
56
+ { name: 'policy', value: @container.find('input[name="policy"]').val() },
57
+ { name: 'signature', value: @container.find('input[name="signature"]').val() },
58
+ { name: 'file', value: @file }
59
+ ]
60
+
61
+
62
+ isUploadStarting: =>
63
+ @container.find('.fileupload').hasClass('fileupload-new')
64
+
65
+ id: =>
66
+ @_id ||= uuid.v4()
67
+
68
+ progress: (data) =>
69
+ progress = parseInt(data.loaded / data.total * 100, 10)
70
+ @loader.find('.bar').css({width: progress + '%'})
71
+
72
+ done: (data) =>
73
+ @container.find('.fileupload').removeClass('uploading').addClass('processing')
74
+ $.ajax
75
+ type: 'POST'
76
+ url: @fileInput.data('callback-url')
77
+ data:
78
+ 'image[remote_file_url]': @fileInput.data('url') + @filePath
79
+ 'image[imageable_type]': @typeInput.val()
80
+ 'image[upload_name]': @uploadNameInput.val()
81
+ 'image[secure_random]': @id()
82
+
83
+ complete: =>
84
+ @verifyProcessingInterval = setInterval(@verifyProcessing, 5000)
85
+
86
+ error: =>
87
+ @loader.detach()
88
+ @container.find('.fileupload').removeClass('uploading').removeClass('processing')
89
+ @container.closest('form').find('[type=submit]').attr("disabled", false)
90
+
91
+ verifyProcessing: =>
92
+ arr = @filePath.split('/')
93
+ filename = arr[arr.length - 1]
94
+ $.ajax
95
+ type: 'GET'
96
+ dataType: 'json'
97
+ url: @fileInput.data('find-url')
98
+ data:
99
+ 'name': filename
100
+ 'imageable_type': @typeInput.val()
101
+ 'upload_name': @uploadNameInput.val()
102
+ 'secure_random': @id()
103
+
104
+ complete: (data) =>
105
+ if data.responseJSON.hasOwnProperty('id')
106
+ clearInterval(@verifyProcessingInterval)
107
+ @showThumb(data.responseJSON)
108
+
109
+ error: =>
110
+ @loader.detach()
111
+ @container.detach()
112
+
113
+ showThumb: (image) =>
114
+ @loader.detach()
115
+ @idInput.val(image.id)
116
+ @container.find('a.btn.fileupload-exists').attr('href', image.url)
117
+ @thumbContainer.find('img').detach()
118
+ img = $('<img/>')
119
+ img.attr('src', image.versions[@thumbContainer.data('version')])
120
+ img.attr('width', @thumbContainer.data('width'))
121
+ img.attr('height', @thumbContainer.data('height')).hide()
122
+ @container.find('.fileupload-preview.thumbnail').append(img.fadeIn())
123
+ @container.find('.fileupload').removeClass('fileupload-new').addClass('fileupload-exists')
124
+ @container.find('.fileupload').removeClass('uploading').removeClass('processing')
125
+ @container.closest('form').find('[type=submit]').attr("disabled", false)
126
+
127
+ fail: =>
128
+ @loader.detach()
129
+ @container.detach()
130
+
131
+ delete: =>
132
+ @idInput.val('')
133
+ @container.detach()
134
+
@@ -0,0 +1,245 @@
1
+ // uuid.js
2
+ //
3
+ // Copyright (c) 2010-2012 Robert Kieffer
4
+ // MIT License - http://opensource.org/licenses/mit-license.php
5
+
6
+ (function() {
7
+ var _global = this;
8
+
9
+ // Unique ID creation requires a high quality random # generator. We feature
10
+ // detect to determine the best RNG source, normalizing to a function that
11
+ // returns 128-bits of randomness, since that's what's usually required
12
+ var _rng;
13
+
14
+ // Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html
15
+ //
16
+ // Moderately fast, high quality
17
+ if (typeof(_global.require) == 'function') {
18
+ try {
19
+ var _rb = _global.require('crypto').randomBytes;
20
+ _rng = _rb && function() {return _rb(16);};
21
+ } catch(e) {}
22
+ }
23
+
24
+ if (!_rng && _global.crypto && crypto.getRandomValues) {
25
+ // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
26
+ //
27
+ // Moderately fast, high quality
28
+ var _rnds8 = new Uint8Array(16);
29
+ _rng = function whatwgRNG() {
30
+ crypto.getRandomValues(_rnds8);
31
+ return _rnds8;
32
+ };
33
+ }
34
+
35
+ if (!_rng) {
36
+ // Math.random()-based (RNG)
37
+ //
38
+ // If all else fails, use Math.random(). It's fast, but is of unspecified
39
+ // quality.
40
+ var _rnds = new Array(16);
41
+ _rng = function() {
42
+ for (var i = 0, r; i < 16; i++) {
43
+ if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
44
+ _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
45
+ }
46
+
47
+ return _rnds;
48
+ };
49
+ }
50
+
51
+ // Buffer class to use
52
+ var BufferClass = typeof(_global.Buffer) == 'function' ? _global.Buffer : Array;
53
+
54
+ // Maps for number <-> hex string conversion
55
+ var _byteToHex = [];
56
+ var _hexToByte = {};
57
+ for (var i = 0; i < 256; i++) {
58
+ _byteToHex[i] = (i + 0x100).toString(16).substr(1);
59
+ _hexToByte[_byteToHex[i]] = i;
60
+ }
61
+
62
+ // **`parse()` - Parse a UUID into it's component bytes**
63
+ function parse(s, buf, offset) {
64
+ var i = (buf && offset) || 0, ii = 0;
65
+
66
+ buf = buf || [];
67
+ s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
68
+ if (ii < 16) { // Don't overflow!
69
+ buf[i + ii++] = _hexToByte[oct];
70
+ }
71
+ });
72
+
73
+ // Zero out remaining bytes if string was short
74
+ while (ii < 16) {
75
+ buf[i + ii++] = 0;
76
+ }
77
+
78
+ return buf;
79
+ }
80
+
81
+ // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
82
+ function unparse(buf, offset) {
83
+ var i = offset || 0, bth = _byteToHex;
84
+ return bth[buf[i++]] + bth[buf[i++]] +
85
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
86
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
87
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
88
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
89
+ bth[buf[i++]] + bth[buf[i++]] +
90
+ bth[buf[i++]] + bth[buf[i++]] +
91
+ bth[buf[i++]] + bth[buf[i++]];
92
+ }
93
+
94
+ // **`v1()` - Generate time-based UUID**
95
+ //
96
+ // Inspired by https://github.com/LiosK/UUID.js
97
+ // and http://docs.python.org/library/uuid.html
98
+
99
+ // random #'s we need to init node and clockseq
100
+ var _seedBytes = _rng();
101
+
102
+ // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
103
+ var _nodeId = [
104
+ _seedBytes[0] | 0x01,
105
+ _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
106
+ ];
107
+
108
+ // Per 4.2.2, randomize (14 bit) clockseq
109
+ var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
110
+
111
+ // Previous uuid creation time
112
+ var _lastMSecs = 0, _lastNSecs = 0;
113
+
114
+ // See https://github.com/broofa/node-uuid for API details
115
+ function v1(options, buf, offset) {
116
+ var i = buf && offset || 0;
117
+ var b = buf || [];
118
+
119
+ options = options || {};
120
+
121
+ var clockseq = options.clockseq != null ? options.clockseq : _clockseq;
122
+
123
+ // UUID timestamps are 100 nano-second units since the Gregorian epoch,
124
+ // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
125
+ // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
126
+ // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
127
+ var msecs = options.msecs != null ? options.msecs : new Date().getTime();
128
+
129
+ // Per 4.2.1.2, use count of uuid's generated during the current clock
130
+ // cycle to simulate higher resolution clock
131
+ var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1;
132
+
133
+ // Time since last uuid creation (in msecs)
134
+ var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
135
+
136
+ // Per 4.2.1.2, Bump clockseq on clock regression
137
+ if (dt < 0 && options.clockseq == null) {
138
+ clockseq = clockseq + 1 & 0x3fff;
139
+ }
140
+
141
+ // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
142
+ // time interval
143
+ if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
144
+ nsecs = 0;
145
+ }
146
+
147
+ // Per 4.2.1.2 Throw error if too many uuids are requested
148
+ if (nsecs >= 10000) {
149
+ throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
150
+ }
151
+
152
+ _lastMSecs = msecs;
153
+ _lastNSecs = nsecs;
154
+ _clockseq = clockseq;
155
+
156
+ // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
157
+ msecs += 12219292800000;
158
+
159
+ // `time_low`
160
+ var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
161
+ b[i++] = tl >>> 24 & 0xff;
162
+ b[i++] = tl >>> 16 & 0xff;
163
+ b[i++] = tl >>> 8 & 0xff;
164
+ b[i++] = tl & 0xff;
165
+
166
+ // `time_mid`
167
+ var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
168
+ b[i++] = tmh >>> 8 & 0xff;
169
+ b[i++] = tmh & 0xff;
170
+
171
+ // `time_high_and_version`
172
+ b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
173
+ b[i++] = tmh >>> 16 & 0xff;
174
+
175
+ // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
176
+ b[i++] = clockseq >>> 8 | 0x80;
177
+
178
+ // `clock_seq_low`
179
+ b[i++] = clockseq & 0xff;
180
+
181
+ // `node`
182
+ var node = options.node || _nodeId;
183
+ for (var n = 0; n < 6; n++) {
184
+ b[i + n] = node[n];
185
+ }
186
+
187
+ return buf ? buf : unparse(b);
188
+ }
189
+
190
+ // **`v4()` - Generate random UUID**
191
+
192
+ // See https://github.com/broofa/node-uuid for API details
193
+ function v4(options, buf, offset) {
194
+ // Deprecated - 'format' argument, as supported in v1.2
195
+ var i = buf && offset || 0;
196
+
197
+ if (typeof(options) == 'string') {
198
+ buf = options == 'binary' ? new BufferClass(16) : null;
199
+ options = null;
200
+ }
201
+ options = options || {};
202
+
203
+ var rnds = options.random || (options.rng || _rng)();
204
+
205
+ // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
206
+ rnds[6] = (rnds[6] & 0x0f) | 0x40;
207
+ rnds[8] = (rnds[8] & 0x3f) | 0x80;
208
+
209
+ // Copy bytes to buffer, if provided
210
+ if (buf) {
211
+ for (var ii = 0; ii < 16; ii++) {
212
+ buf[i + ii] = rnds[ii];
213
+ }
214
+ }
215
+
216
+ return buf || unparse(rnds);
217
+ }
218
+
219
+ // Export public API
220
+ var uuid = v4;
221
+ uuid.v1 = v1;
222
+ uuid.v4 = v4;
223
+ uuid.parse = parse;
224
+ uuid.unparse = unparse;
225
+ uuid.BufferClass = BufferClass;
226
+
227
+ if (typeof define === 'function' && define.amd) {
228
+ // Publish as AMD module
229
+ define(function() {return uuid;});
230
+ } else if (typeof(module) != 'undefined' && module.exports) {
231
+ // Publish as node.js module
232
+ module.exports = uuid;
233
+ } else {
234
+ // Publish as global (in browsers)
235
+ var _previousRoot = _global.uuid;
236
+
237
+ // **`noConflict()` - (browser only) to reset global 'uuid' var**
238
+ uuid.noConflict = function() {
239
+ _global.uuid = _previousRoot;
240
+ return uuid;
241
+ };
242
+
243
+ _global.uuid = uuid;
244
+ }
245
+ }).call(this);
@@ -2,5 +2,9 @@
2
2
  #= require jquery.iframe-transport
3
3
  #= require cors/jquery.postmessage-transport
4
4
  #= require cors/jquery.xdr-transport
5
+ #= require _uuid
5
6
  #= require jquery.fileupload
6
7
  #= require _image_uploader
8
+ #= require _uploader_preview
9
+ #= require _gallery_uploader
10
+ #= require _manager
@@ -1,10 +1,10 @@
1
1
  @font-face {
2
2
  font-family: 'fontello';
3
- src: url('fontello.eot?99792958');
4
- src: url('fontello.eot?99792958#iefix') format('embedded-opentype'),
5
- url('fontello.woff?99792958') format('woff'),
6
- url('fontello.ttf?99792958') format('truetype'),
7
- url('fontello.svg?99792958#fontello') format('svg');
3
+ src: url('fontello.eot?18809145');
4
+ src: url('fontello.eot?18809145#iefix') format('embedded-opentype'),
5
+ url('fontello.woff?18809145') format('woff'),
6
+ url('fontello.ttf?18809145') format('truetype'),
7
+ url('fontello.svg?18809145#fontello') format('svg');
8
8
  font-weight: normal;
9
9
  font-style: normal;
10
10
  }
@@ -14,7 +14,7 @@
14
14
  @media screen and (-webkit-min-device-pixel-ratio:0) {
15
15
  @font-face {
16
16
  font-family: 'fontello';
17
- src: url('../font/fontello.svg?99792958#fontello') format('svg');
17
+ src: url('../font/fontello.svg?18809145#fontello') format('svg');
18
18
  }
19
19
  }
20
20
  */
@@ -50,4 +50,5 @@
50
50
  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
51
51
  }
52
52
 
53
- .icon-picture-1:before { content: '\e800'; } /* '' */
53
+ .icon-picture-1:before { content: '\e800'; } /* '' */
54
+ .icon-plus-1:before { content: '\e802'; } /* '' */
@@ -3,7 +3,6 @@
3
3
 
4
4
  .uploadbox-image-uploader
5
5
  position: relative
6
- padding-bottom: 30px
7
6
 
8
7
  .btn
9
8
  background-color: #f7f7f7
@@ -15,18 +14,17 @@
15
14
  .btn
16
15
  border: 1px solid darken(#f7f7f7, 20%)
17
16
 
18
- .icon-picture-1
17
+ .icon
19
18
  opacity: .5
20
19
 
21
20
  .fileupload-exists
22
- .icon-picture-1
21
+ .icon
23
22
  display: none
24
23
 
25
- .icon-picture-1
24
+ .icon
26
25
  position: absolute
27
26
  top: 0
28
27
  left: 0
29
- font-size: 40px
30
28
  width: 100%
31
29
  height: 100%
32
30
  opacity: .3
@@ -0,0 +1,61 @@
1
+ = form.fields_for :image do
2
+ div data-component="GalleryUploader"
3
+ .uploadbox-image-uploader.uploads-many data-container="uploader" style="width: #{width}px; height: #{height}px;"
4
+ - if namespace
5
+ input name="[#{resource.class.name.underscore}][#{namespace}]#{upload_name}[]" data-item="id" type="hidden"
6
+ - else
7
+ input name="[#{resource.class.name.underscore}]#{upload_name}[]" data-item="id" type="hidden"
8
+
9
+ .fileupload data-provides="fileupload" class="fileupload-new"
10
+ .fileupload-preview.thumbnail data-version="#{version}" data-width="#{width}" data-height="#{height}" style="width: #{width}px; height: #{height}px;"
11
+
12
+ .fileupload-actions
13
+ span.btn.btn-file style="width: #{width}px; height: #{height}px;"
14
+ span.fileupload-new = choose_label
15
+ span.fileupload-exists = update_label
16
+ i.icon.icon-plus-1 style="line-height: #{height}px; font-size: #{(width * 0.4).to_i}px"
17
+
18
+ input type="file" name="image[file]" data-callback-url="#{uploadbox.images_path}" data-find-url="#{uploadbox.find_images_path(format: :json)}" data-url="https://#{ENV['S3_BUCKET']}.s3.amazonaws.com/" accept="image/png image/x-png, image/gif, image/jpeg" style="display: none; width: #{width}px; height: #{height}px;" multiple="true"
19
+ input type="hidden" name="policy" value="#{s3_policy}"
20
+ input type="hidden" name="signature" value="#{s3_signature}"
21
+ input type="hidden" name="AWSAccessKeyId" value="#{ENV['S3_KEY']}"
22
+ input type="hidden" name="acl" value="public-read"
23
+ input type="hidden" name="key"
24
+
25
+ input type="hidden" name="image[imageable_type]" value="#{resource.class}"
26
+ input type="hidden" name="image[upload_name]" value="#{upload_name}"
27
+ - if removable
28
+ - if resource.send(upload_name).present?
29
+ = link_to destroy_label, uploadbox.image_path(resource.send(upload_name)), class: 'btn fileupload-exists', remote: true, method: :delete
30
+ - else
31
+ = link_to destroy_label, '#', class: 'btn fileupload-exists', remote: true, method: :delete
32
+
33
+ - for image in resource.send(upload_name)
34
+ .uploadbox-image-uploader.uploads-many data-component="UploaderPreview" data-container="uploader" style="width: #{width}px; height: #{height}px;"
35
+ - if namespace
36
+ input name="[#{resource.class.name.underscore}][#{namespace}]#{upload_name}[]" data-item="id" type="hidden" value="#{image.id}"
37
+ - else
38
+ input name="[#{resource.class.name.underscore}]#{upload_name}[]" data-item="id" type="hidden" value="#{image.id}"
39
+
40
+ .fileupload data-provides="fileupload" class="fileupload-exists"
41
+ .fileupload-preview.thumbnail data-version="#{version}" data-width="#{width}" data-height="#{height}" style="width: #{width}px; height: #{height}px;"
42
+ = img image.send(version)
43
+
44
+ .fileupload-actions
45
+ span.btn.btn-file style="width: #{width}px; height: #{height}px;"
46
+ span.fileupload-new = choose_label
47
+ span.fileupload-exists = update_label
48
+ i.icon.icon-plus-1 style="line-height: #{height}px; font-size: #{(width * 0.4).to_i}px"
49
+
50
+ input type="file" name="image[file]" data-callback-url="#{uploadbox.images_path}" data-find-url="#{uploadbox.find_images_path(format: :json)}" data-url="https://#{ENV['S3_BUCKET']}.s3.amazonaws.com/" accept="image/png image/x-png, image/gif, image/jpeg" style="display: none; width: #{width}px; height: #{height}px;" multiple="true"
51
+ input type="hidden" name="policy" value="#{s3_policy}"
52
+ input type="hidden" name="signature" value="#{s3_signature}"
53
+ input type="hidden" name="AWSAccessKeyId" value="#{ENV['S3_KEY']}"
54
+ input type="hidden" name="acl" value="public-read"
55
+ input type="hidden" name="key"
56
+
57
+ input type="hidden" name="image[imageable_type]" value="#{resource.class}"
58
+ input type="hidden" name="image[upload_name]" value="#{upload_name}"
59
+ - if removable
60
+ = link_to destroy_label, uploadbox.image_path(image), class: 'btn fileupload-exists', remote: true, method: :delete
61
+
@@ -1,10 +1,11 @@
1
1
  = form.fields_for :image do
2
2
  - secure_random = SecureRandom.uuid
3
- .uploadbox-image-uploader data-component="ImageUploader" style="width: #{width}px; height: #{height}px;"
3
+ .uploadbox-image-uploader.uploads-one data-component="ImageUploader" style="width: #{width}px; height: #{height}px;"
4
4
  - if namespace
5
- input name="[#{namespace}]#{upload_name}_id" data-item="id" type="hidden" value="#{resource.send(upload_name).try :id}"
5
+ input name="[#{resource.class.name.underscore}][#{namespace}]#{upload_name}" data-item="id" type="hidden" value="#{resource.send(upload_name).try :id}"
6
6
  - else
7
- input name="#{upload_name}_id" data-item="id" type="hidden" value="#{resource.send(upload_name).try :id}"
7
+ input name="[#{resource.class.name.underscore}]#{upload_name}" data-item="id" type="hidden" value="#{resource.send(upload_name).try :id}"
8
+
8
9
  .fileupload data-provides="fileupload" class="fileupload-#{(resource.send("#{upload_name}?") or default) ? 'exists' : 'new'}"
9
10
  .fileupload-preview.thumbnail data-version="#{version}" data-width="#{width}" data-height="#{height}" style="width: #{width}px; height: #{height}px;"
10
11
  - if resource.send("#{upload_name}?")
@@ -16,8 +17,10 @@
16
17
  span.btn.btn-file style="width: #{width}px; height: #{height}px;"
17
18
  span.fileupload-new = choose_label
18
19
  span.fileupload-exists = update_label
19
- i.icon-picture-1 style="line-height: #{height}px"
20
- input type="file" name="image[file]" data-callback-url="#{uploadbox.images_path}" data-find-url="#{uploadbox.find_images_path(format: :json)}" data-url="https://#{ENV['S3_BUCKET']}.s3.amazonaws.com/" data-secure-random="#{secure_random}" accept="image/x-png, image/gif, image/jpeg" style="display: none; width: #{width}px; height: #{height}px;"
20
+ i.icon.icon-picture-1 style="line-height: #{height}px; font-size: #{(width * 0.4).to_i}px"
21
+
22
+
23
+ input type="file" name="image[file]" data-callback-url="#{uploadbox.images_path}" data-find-url="#{uploadbox.find_images_path(format: :json)}" data-url="https://#{ENV['S3_BUCKET']}.s3.amazonaws.com/" data-secure-random="#{secure_random}" accept="image/png image/x-png, image/gif, image/jpeg" style="display: none; width: #{width}px; height: #{height}px;"
21
24
  input type="hidden" name="policy" value="#{s3_policy}"
22
25
  input type="hidden" name="signature" value="#{s3_signature}"
23
26
  input type="hidden" name="AWSAccessKeyId" value="#{ENV['S3_KEY']}"
data/config/spring.rb ADDED
@@ -0,0 +1 @@
1
+ Spring.application_root = './spec/dummy'
@@ -28,7 +28,7 @@ module Uploadbox
28
28
  end
29
29
 
30
30
  class ActionView::Helpers::FormBuilder
31
- def uploader(upload_name, options={})
31
+ def uploads_one(upload_name, options={})
32
32
  upload_model_class = "Uploadbox::#{@object.class.to_s + upload_name.to_s.camelize}".constantize
33
33
  options.reverse_merge!(preview: upload_model_class.versions.keys.first,
34
34
  namespace: false,
@@ -37,7 +37,32 @@ class ActionView::Helpers::FormBuilder
37
37
  choose_label: 'Escolher',
38
38
  destroy_label: '&times;'.html_safe)
39
39
  dimensions = upload_model_class.versions[options[:preview]]
40
- @template.render partial: 'uploadbox/images/uploader', locals: {
40
+ @template.render partial: 'uploadbox/images/uploads_one', locals: {
41
+ upload_name: upload_name,
42
+ resource: @object,
43
+ form: self,
44
+ version: options[:preview],
45
+ width: dimensions[0],
46
+ height: dimensions[1],
47
+ namespace: options[:namespace],
48
+ default: options[:default],
49
+ removable: upload_model_class.removable?,
50
+ update_label: options[:update_label],
51
+ choose_label: options[:choose_label],
52
+ destroy_label: options[:destroy_label]
53
+ }
54
+ end
55
+
56
+ def uploads_many(upload_name, options={})
57
+ upload_model_class = "Uploadbox::#{@object.class.to_s + upload_name.to_s.camelize}".constantize
58
+ options.reverse_merge!(preview: upload_model_class.versions.keys.first,
59
+ namespace: false,
60
+ default: false,
61
+ update_label: 'Alterar',
62
+ choose_label: 'Escolher',
63
+ destroy_label: '&times;'.html_safe)
64
+ dimensions = upload_model_class.versions[options[:preview]]
65
+ @template.render partial: 'uploadbox/images/uploads_many', locals: {
41
66
  upload_name: upload_name,
42
67
  resource: @object,
43
68
  form: self,
@@ -54,4 +79,4 @@ class ActionView::Helpers::FormBuilder
54
79
  end
55
80
  end
56
81
 
57
- require 'uploadbox/image_uploader'
82
+ require 'uploadbox/image_uploader'
@@ -23,6 +23,7 @@ module Uploadbox
23
23
  upload and upload.file?
24
24
  end
25
25
 
26
+ # @post.picture
26
27
  define_method(upload_name) do
27
28
  upload = send("#{upload_name}_upload")
28
29
 
@@ -48,22 +49,15 @@ module Uploadbox
48
49
  end
49
50
  end
50
51
 
51
- # @post.attach_picture
52
- define_method("attach_#{upload_name}") do |upload_id|
53
- if upload_id.present?
54
- self.send("attach_#{upload_name}!", upload_id)
55
- end
52
+ # @post.picture=(id)
53
+ define_method("#{upload_name}=") do |upload_id|
54
+ self.send("#{upload_name}_upload=", upload_class.find(upload_id))
56
55
  end
57
56
 
58
57
  # @post.remote_picture_url=('http://exemple.com/image.jpg')
59
58
  define_method("remote_#{upload_name}_url=") do |url|
60
59
  upload = Uploadbox.const_get(upload_class_name).create!(remote_file_url: url)
61
- self.send("#{upload_name}=", upload)
62
- end
63
-
64
- # @post.attach_picture!
65
- define_method("attach_#{upload_name}!") do |upload_id|
66
- self.send("#{upload_name}=", upload_class.find(upload_id))
60
+ self.send("#{upload_name}_upload=", upload)
67
61
  end
68
62
 
69
63
  # Post.update_picture_versions!
@@ -80,6 +74,94 @@ module Uploadbox
80
74
  options[:removable]
81
75
  end
82
76
 
77
+ upload_class.instance_eval do
78
+ delegate *upload_versions.keys, to: :file
79
+
80
+ default_scope -> { where(imageable_type: imageable_type).where(upload_name: upload_name.to_s) }
81
+
82
+ # Uploabox::PostPictureUploader < UploadBox::ImgProcessing < CarrierWave
83
+ dynamic_uploader = Class.new(Uploadbox::ImageProcessingUploader)
84
+ Uploadbox.const_set(self.name.demodulize + 'Uploader', dynamic_uploader)
85
+ dynamic_uploader.class_eval do
86
+ upload_versions.each do |version_name, dimensions|
87
+ if options[:retina]
88
+ dimensions = dimensions.map{ |d| d * 2 }
89
+ end
90
+
91
+ version version_name do
92
+ process resize_to_fill: dimensions
93
+ process quality: quality = options[:quality]
94
+ end
95
+
96
+ def dimensions
97
+ model.class.versions[version_name]
98
+ end
99
+
100
+ def width
101
+ dimensions[0]
102
+ end
103
+
104
+ def height
105
+ dimensions[1]
106
+ end
107
+ end
108
+ end
109
+ mount_uploader :file, dynamic_uploader
110
+
111
+ end
112
+
113
+ has_one "#{upload_name}_upload".to_sym, as: :imageable,
114
+ class_name: "Uploadbox::#{self.to_s + upload_name.to_s.camelize}",
115
+ autosave: true
116
+ accepts_nested_attributes_for "#{upload_name}_upload".to_sym
117
+ end
118
+
119
+
120
+ def uploads_many(upload_name, options={})
121
+ default_options = {
122
+ default: false,
123
+ placeholder: false,
124
+ removable: true,
125
+ retina: Uploadbox.retina,
126
+ quality: Uploadbox.retina ? (Uploadbox.retina_quality || 40) : (Uploadbox.image_quality || 80)
127
+ }
128
+ options = options.reverse_merge(default_options)
129
+ upload_versions = options.select{ |key| default_options.keys.exclude? key }
130
+ options = options.select{ |key| default_options.keys.include? key }
131
+
132
+ imageable_type = self.to_s
133
+ upload_class_name = imageable_type + upload_name.to_s.camelize
134
+ upload_class = Class.new(Image)
135
+ Uploadbox.const_set(upload_class_name, upload_class)
136
+
137
+ # @post.images?
138
+ define_method("#{upload_name}?") do
139
+ upload = send(upload_name)
140
+ upload and upload.any?
141
+ end
142
+
143
+ # @post.images=([id, id])
144
+ define_method("#{upload_name}=") do |ids|
145
+ self.send(upload_name).send('replace', [])
146
+ for id in ids.select(&:present?)
147
+ self.send(upload_name).send('<<', upload_class.find(id))
148
+ end
149
+ end
150
+
151
+ # Post.update_images_versions!
152
+ self.define_singleton_method "update_#{upload_name}_versions!" do
153
+ Uploadbox.const_get(upload_class_name).find_each{|upload| upload.file.recreate_versions!}
154
+ end
155
+
156
+ # Uploadbox::PostImages < Image
157
+ upload_class.define_singleton_method :versions do
158
+ upload_versions
159
+ end
160
+
161
+ upload_class.define_singleton_method :removable? do
162
+ options[:removable]
163
+ end
164
+
83
165
  upload_class.instance_eval do
84
166
  delegate *upload_versions.keys, to: :file
85
167
 
@@ -115,7 +197,7 @@ module Uploadbox
115
197
  mount_uploader :file, dynamic_uploader
116
198
  end
117
199
 
118
- has_one "#{upload_name}_upload".to_sym, as: :imageable, dependent: :destroy, class_name: "Uploadbox::#{self.to_s + upload_name.to_s.camelize}"
200
+ has_many upload_name, as: :imageable, class_name: "Uploadbox::#{self.to_s + upload_name.to_s.camelize}"
119
201
  end
120
202
 
121
203
  end
@@ -1,3 +1,3 @@
1
1
  module Uploadbox
2
- VERSION = "0.0.13"
2
+ VERSION = "0.0.14"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uploadbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julio Protzek
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-17 00:00:00.000000000 Z
12
+ date: 2013-10-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -347,6 +347,34 @@ dependencies:
347
347
  - - ~>
348
348
  - !ruby/object:Gem::Version
349
349
  version: 0.3.2
350
+ - !ruby/object:Gem::Dependency
351
+ name: dotenv-rails
352
+ requirement: !ruby/object:Gem::Requirement
353
+ requirements:
354
+ - - '>='
355
+ - !ruby/object:Gem::Version
356
+ version: '0'
357
+ type: :development
358
+ prerelease: false
359
+ version_requirements: !ruby/object:Gem::Requirement
360
+ requirements:
361
+ - - '>='
362
+ - !ruby/object:Gem::Version
363
+ version: '0'
364
+ - !ruby/object:Gem::Dependency
365
+ name: launchy
366
+ requirement: !ruby/object:Gem::Requirement
367
+ requirements:
368
+ - - '>='
369
+ - !ruby/object:Gem::Version
370
+ version: '0'
371
+ type: :development
372
+ prerelease: false
373
+ version_requirements: !ruby/object:Gem::Requirement
374
+ requirements:
375
+ - - '>='
376
+ - !ruby/object:Gem::Version
377
+ version: '0'
350
378
  description: Uploadbox makes easy to manage files in your Rails application.
351
379
  email:
352
380
  - julio@startae.com.br
@@ -359,7 +387,11 @@ files:
359
387
  - app/assets/font/fontello.svg
360
388
  - app/assets/font/fontello.ttf
361
389
  - app/assets/font/fontello.woff
390
+ - app/assets/javascripts/_gallery_uploader.coffee
362
391
  - app/assets/javascripts/_image_uploader.coffee
392
+ - app/assets/javascripts/_manager.coffee
393
+ - app/assets/javascripts/_uploader_preview.coffee
394
+ - app/assets/javascripts/_uuid.js
363
395
  - app/assets/javascripts/cors/jquery.postmessage-transport.js
364
396
  - app/assets/javascripts/cors/jquery.xdr-transport.js
365
397
  - app/assets/javascripts/jquery.fileupload.js
@@ -367,7 +399,7 @@ files:
367
399
  - app/assets/javascripts/jquery.ui.widget.js
368
400
  - app/assets/javascripts/uploadbox.coffee
369
401
  - app/assets/stylesheets/bootstrap/_progress.css
370
- - app/assets/stylesheets/fontello.scss
402
+ - app/assets/stylesheets/fontello.css
371
403
  - app/assets/stylesheets/uploadbox.sass
372
404
  - app/controllers/uploadbox/application_controller.rb
373
405
  - app/controllers/uploadbox/images_controller.rb
@@ -377,9 +409,11 @@ files:
377
409
  - app/models/image.rb
378
410
  - app/uploaders/uploadbox/image_processing_uploader.rb
379
411
  - app/views/layouts/uploadbox/application.html.erb
380
- - app/views/uploadbox/images/_uploader.html.slim
412
+ - app/views/uploadbox/images/_uploads_many.slim
413
+ - app/views/uploadbox/images/_uploads_one.slim
381
414
  - app/views/uploadbox/images/find.json.jbuilder
382
415
  - config/routes.rb
416
+ - config/spring.rb
383
417
  - lib/form_builder.rb
384
418
  - lib/generators/uploadbox/image/image_generator.rb
385
419
  - lib/generators/uploadbox/image/templates/initializers/uploadbox.rb