simple_form_bs5_file_input 0.2.1 → 0.3.0
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/Gemfile +0 -1
- data/Gemfile.lock +1 -6
- data/README.md +1 -3
- data/assets/javascripts/polyfills/element_closest.js +18 -0
- data/assets/javascripts/simple_form_bs5_file_input.js +124 -101
- data/lib/simple_form_bs5_file_input/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c053d9cb8619604bb12aeeca15ec00bba955b93189dce35eecc776bf65d99d3
|
|
4
|
+
data.tar.gz: 3d46643934e4229fd26f90027c2cda2d2939ed1d8b15c010bf2209c4a7dc9c40
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c82a7860aea72365d85d4d56bb2eb2cc9799d6190b0b3dc63161f2b8ec592ec7f695ee788ce25b4d43df043085d519485e869c0be6154824cc23592c43c6f947
|
|
7
|
+
data.tar.gz: cce043be273e5c0d2519f55a6a0c79e108d968da87a68cb5325e501c44c46f4810477bc42846c82462766f84792da9c7913e8655b96c4cd5097d09adf58347ed
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
simple_form_bs5_file_input (0.
|
|
4
|
+
simple_form_bs5_file_input (0.3.0)
|
|
5
5
|
rails
|
|
6
6
|
simple_form
|
|
7
7
|
|
|
@@ -115,10 +115,6 @@ GEM
|
|
|
115
115
|
irb (1.12.0)
|
|
116
116
|
rdoc
|
|
117
117
|
reline (>= 0.4.2)
|
|
118
|
-
jquery-rails (4.6.0)
|
|
119
|
-
rails-dom-testing (>= 1, < 3)
|
|
120
|
-
railties (>= 4.2.0)
|
|
121
|
-
thor (>= 0.14, < 2.0)
|
|
122
118
|
listen (3.9.0)
|
|
123
119
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
|
124
120
|
rb-inotify (~> 0.9, >= 0.9.10)
|
|
@@ -228,7 +224,6 @@ DEPENDENCIES
|
|
|
228
224
|
bootsnap (>= 1.4.4)
|
|
229
225
|
bootstrap
|
|
230
226
|
devise
|
|
231
|
-
jquery-rails
|
|
232
227
|
listen
|
|
233
228
|
pg (~> 1.1)
|
|
234
229
|
simple_form
|
data/README.md
CHANGED
|
@@ -110,15 +110,13 @@ Add `resize: true` to your field.
|
|
|
110
110
|
You can also specify a ratio for the cropper. For example `resize: 1` will lock the aspect ratio to a square. Beware of the float constraints in rails. If you want a 4/3 ratio use `resize: 4/3.to_f` as 4/3 otherwise gives 1.
|
|
111
111
|
|
|
112
112
|
|
|
113
|
-
The resizer is based on [CropperJS](https://github.com/fengyuanchen/cropperjs) so you have to add cropper
|
|
113
|
+
The resizer is based on [CropperJS](https://github.com/fengyuanchen/cropperjs) so you have to add cropper to your dependencies:
|
|
114
114
|
```
|
|
115
115
|
yarn add cropperjs
|
|
116
|
-
yarn add jquery-cropper
|
|
117
116
|
```
|
|
118
117
|
then include the js files in your application.js file:
|
|
119
118
|
```
|
|
120
119
|
//= require cropperjs/dist/cropper
|
|
121
|
-
//= require jquery-cropper/dist/jquery-cropper
|
|
122
120
|
```
|
|
123
121
|
and include the css in your application.sass file:
|
|
124
122
|
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
if (typeof Element !== "undefined") {
|
|
2
|
+
if (!Element.prototype.matches) {
|
|
3
|
+
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
if (!Element.prototype.closest) {
|
|
7
|
+
Element.prototype.closest = function (s) {
|
|
8
|
+
var el = this;
|
|
9
|
+
|
|
10
|
+
do {
|
|
11
|
+
if (el.matches(s)) return el;
|
|
12
|
+
el = el.parentElement || el.parentNode;
|
|
13
|
+
} while (el !== null && el.nodeType === 1);
|
|
14
|
+
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,26 +1,33 @@
|
|
|
1
|
-
|
|
1
|
+
//= require polyfills/element_closest.js
|
|
2
|
+
|
|
3
|
+
/* eslint no-alert: 0 */
|
|
4
|
+
/*global Cropper, bootstrap */
|
|
5
|
+
|
|
2
6
|
window.inputSingleDeletableFile = {
|
|
7
|
+
cropperInstances: [],
|
|
3
8
|
onFileDelete: function (e) {
|
|
4
9
|
'use strict';
|
|
5
|
-
var
|
|
10
|
+
var scope = this.closest('.js-sdfi-deletable-file');
|
|
11
|
+
|
|
6
12
|
e.preventDefault();
|
|
7
13
|
e.stopPropagation();
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
|
|
15
|
+
scope.querySelector('.js-sdfi-deletable-file__infos-field').value = '';
|
|
16
|
+
scope.querySelector('.js-sdfi-deletable-file__delete-field').value = true;
|
|
17
|
+
scope.querySelector('input[type="file"]').value = '';
|
|
18
|
+
|
|
19
|
+
scope.classList.remove('sdfi-deletable-file--with-file');
|
|
12
20
|
},
|
|
13
21
|
|
|
14
22
|
onFileSelected: function () {
|
|
15
23
|
'use strict';
|
|
16
|
-
var
|
|
17
|
-
|
|
24
|
+
var scope = this.closest('.js-sdfi-deletable-file'),
|
|
25
|
+
resizeModal = scope.querySelector('.js-sdfi-deletable-file__resize'),
|
|
26
|
+
preview = scope.querySelector('.js-sdfi-deletable-file__preview'),
|
|
18
27
|
files = this.files,
|
|
19
28
|
file,
|
|
20
29
|
isResizable,
|
|
21
30
|
isPreviewable,
|
|
22
|
-
hasPreview = $('.js-sdfi-deletable-file__preview', $scope).length > 0,
|
|
23
|
-
hasResize = $resizeModal.length > 0,
|
|
24
31
|
modal,
|
|
25
32
|
reader,
|
|
26
33
|
size;
|
|
@@ -33,152 +40,168 @@ window.inputSingleDeletableFile = {
|
|
|
33
40
|
isResizable = (/^image\/(png|jpeg)+$/).test(file.type);
|
|
34
41
|
isPreviewable = (/^image\/[a-z+]+$/).test(file.type);
|
|
35
42
|
|
|
36
|
-
if (isResizable &&
|
|
43
|
+
if (isResizable && resizeModal || isPreviewable && preview) {
|
|
37
44
|
reader = new FileReader();
|
|
38
45
|
reader.readAsDataURL(file);
|
|
39
|
-
if (isResizable &&
|
|
46
|
+
if (isResizable && resizeModal) {
|
|
40
47
|
// Resizable images
|
|
41
48
|
reader.onload = function () {
|
|
42
|
-
modal = new bootstrap.Modal(
|
|
49
|
+
modal = new bootstrap.Modal(resizeModal, {
|
|
43
50
|
backdrop: 'static',
|
|
44
51
|
keyboard: false
|
|
45
52
|
});
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
resizeModal.setAttribute('data-image-result', this.result);
|
|
54
|
+
resizeModal.setAttribute('data-filename', file.name);
|
|
48
55
|
modal.show();
|
|
49
56
|
};
|
|
50
57
|
} else {
|
|
51
58
|
// Previewable images
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
size =
|
|
57
|
-
.split('x');
|
|
59
|
+
scope.querySelector('.js-sdfi-deletable-file__infos-field').value = '';
|
|
60
|
+
scope.classList.add('sdfi-deletable-file--with-file');
|
|
61
|
+
scope.querySelector('.js-sdfi-deletable-file__label').innerHTML = file.name;
|
|
62
|
+
scope.querySelector('.js-sdfi-deletable-file__delete-field').value = '';
|
|
63
|
+
size = preview.getAttribute('data-size').split('x');
|
|
58
64
|
reader.onload = function (e) {
|
|
59
|
-
|
|
65
|
+
preview.innerHTML = '<img src="' + e.target.result + '" width="' + size[0] + '" height="auto" class="img-fluid img-thumbnail">';
|
|
60
66
|
};
|
|
61
67
|
}
|
|
62
68
|
} else {
|
|
63
69
|
// Non-resizable and non-previewable files
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
scope.querySelector('.js-sdfi-deletable-file__infos-field').value = '';
|
|
71
|
+
scope.classList.add('sdfi-deletable-file--with-file');
|
|
72
|
+
scope.querySelector('.js-sdfi-deletable-file__label').innerHTML = file.name;
|
|
73
|
+
scope.querySelector('.js-sdfi-deletable-file__delete-field').value = '';
|
|
74
|
+
preview.innerHTML = '';
|
|
69
75
|
}
|
|
70
76
|
},
|
|
71
77
|
|
|
72
78
|
onResizeModalShown: function (e) {
|
|
73
79
|
'use strict';
|
|
74
|
-
var
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
image =
|
|
79
|
-
ratio =
|
|
80
|
+
var modal = e.target,
|
|
81
|
+
scope = modal.closest('.js-sdfi-deletable-file'),
|
|
82
|
+
imgContainer = scope.querySelector('.js-sdfi-sdfi-deletable-file__resize-image'),
|
|
83
|
+
imageElement,
|
|
84
|
+
image = modal.getAttribute('data-image-result'),
|
|
85
|
+
ratio = imgContainer.getAttribute('data-ratio'),
|
|
86
|
+
cropper;
|
|
87
|
+
|
|
88
|
+
imgContainer.innerHTML = '<img class="js-image" src="' + image + '">';
|
|
80
89
|
|
|
81
|
-
|
|
90
|
+
imageElement = imgContainer.querySelector('img');
|
|
91
|
+
imageElement.style.opacity = 0;
|
|
82
92
|
|
|
83
|
-
$image = $('img', $imgContainer);
|
|
84
|
-
$image.css('opacity', 0);
|
|
85
93
|
setTimeout(function () {
|
|
86
94
|
// init cropper with a small delay
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
cropper = new Cropper(imageElement,
|
|
96
|
+
{
|
|
97
|
+
aspectRatio: ratio,
|
|
98
|
+
autoCropArea: 1,
|
|
99
|
+
movable: false,
|
|
100
|
+
guides: false,
|
|
101
|
+
background: false,
|
|
102
|
+
viewMode: 1,
|
|
103
|
+
zoomable: false,
|
|
104
|
+
crop: function (data) {
|
|
105
|
+
scope.querySelector('.js-sdfi-deletable-file__infos-field').value = JSON.stringify(data.detail);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
window.inputSingleDeletableFile.cropperInstances.push(cropper);
|
|
110
|
+
imageElement.setAttribute('data-cropper-index', window.inputSingleDeletableFile.cropperInstances.length - 1);
|
|
111
|
+
|
|
112
|
+
imageElement.style.opacity = 1;
|
|
100
113
|
}, 100);
|
|
101
114
|
},
|
|
102
115
|
|
|
103
116
|
onResizeModalRotate: function (e) {
|
|
104
117
|
'use strict';
|
|
105
|
-
var
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
var scope = e.target.closest('.js-sdfi-deletable-file'),
|
|
119
|
+
imgContainer = scope.querySelector('.js-sdfi-sdfi-deletable-file__resize-image'),
|
|
120
|
+
image = imgContainer.querySelector('img'),
|
|
121
|
+
cropperIndex = parseInt(image.getAttribute('data-cropper-index'), 10),
|
|
122
|
+
cropper = window.inputSingleDeletableFile.cropperInstances[cropperIndex];
|
|
123
|
+
|
|
124
|
+
cropper.rotate(90);
|
|
109
125
|
},
|
|
110
126
|
|
|
111
127
|
onResizeModalCancel: function (e) {
|
|
112
128
|
'use strict';
|
|
113
|
-
var
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
129
|
+
var scope = e.target.closest('.js-sdfi-deletable-file');
|
|
130
|
+
scope.querySelector('.js-sdfi-deletable-file__infos-field').value = '';
|
|
131
|
+
scope.querySelector('.js-sdfi-deletable-file__delete-field').value = '';
|
|
132
|
+
scope.querySelector('input[type="file"]').value = '';
|
|
133
|
+
scope.classList.remove('sdfi-deletable-file--with-file');
|
|
118
134
|
},
|
|
119
135
|
|
|
120
136
|
onResizeModalValidate: function (e) {
|
|
121
137
|
'use strict';
|
|
122
|
-
var
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
filename =
|
|
127
|
-
|
|
138
|
+
var scope = e.target.closest('.js-sdfi-deletable-file'),
|
|
139
|
+
resizeModal = scope.querySelector('.js-sdfi-deletable-file__resize'),
|
|
140
|
+
imgContainer = scope.querySelector('.js-sdfi-sdfi-deletable-file__resize-image'),
|
|
141
|
+
image = imgContainer.querySelector('img'),
|
|
142
|
+
filename = resizeModal.getAttribute('data-filename'),
|
|
143
|
+
preview = scope.querySelector('.js-sdfi-deletable-file__preview'),
|
|
128
144
|
imageData,
|
|
129
|
-
resizeModal = $resizeModal[0],
|
|
130
145
|
modal = bootstrap.Modal.getInstance(resizeModal),
|
|
131
|
-
size
|
|
146
|
+
size,
|
|
147
|
+
cropperIndex = parseInt(image.getAttribute('data-cropper-index'), 10),
|
|
148
|
+
cropper = window.inputSingleDeletableFile.cropperInstances[cropperIndex];
|
|
132
149
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
150
|
+
scope.classList.add('sdfi-deletable-file--with-file');
|
|
151
|
+
scope.querySelector('.js-sdfi-deletable-file__label').innerHTML = filename;
|
|
152
|
+
scope.querySelector('.js-sdfi-deletable-file__delete-field').value = '';
|
|
136
153
|
|
|
137
154
|
// set the preview if we have preview
|
|
138
|
-
if (
|
|
139
|
-
size =
|
|
155
|
+
if (preview) {
|
|
156
|
+
size = preview.getAttribute('data-size')
|
|
140
157
|
.split('x');
|
|
141
|
-
imageData = $image.data('cropper')
|
|
142
|
-
.getCroppedCanvas()
|
|
143
|
-
.toDataURL();
|
|
144
158
|
|
|
145
|
-
|
|
159
|
+
imageData = cropper.getCroppedCanvas().toDataURL();
|
|
160
|
+
|
|
161
|
+
preview.innerHTML = '<img src="' + imageData + '" width="' + size[0] + '" height="auto" class="img-fluid img-thumbnail">';
|
|
146
162
|
}
|
|
147
163
|
modal.hide();
|
|
148
164
|
},
|
|
149
165
|
|
|
150
166
|
bindEvents: function (field) {
|
|
151
167
|
'use strict';
|
|
168
|
+
var resize = field.querySelector('.js-sdfi-deletable-file__resize');
|
|
152
169
|
// click on the fake "replace file" btn launch the file input choice
|
|
153
|
-
|
|
154
|
-
|
|
170
|
+
field.querySelector('.js-sdfi-deletable-file__change-btn').addEventListener('click', function () {
|
|
171
|
+
field.querySelector('input[type="file"]').click();
|
|
155
172
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
173
|
+
|
|
174
|
+
field.querySelector('.js-sdfi-deletable-file__delete-btn').addEventListener('click', this.onFileDelete);
|
|
175
|
+
field.querySelector('input[type="file"]').addEventListener('change', this.onFileSelected);
|
|
176
|
+
|
|
177
|
+
if (resize) {
|
|
178
|
+
resize.addEventListener('shown.bs.modal', this.onResizeModalShown);
|
|
179
|
+
field.querySelector('.js-sdfi-deletable-file__resize-rotate').addEventListener('click', this.onResizeModalRotate);
|
|
180
|
+
field.querySelector('.js-sdfi-deletable-file__resize-cancel').addEventListener('click', this.onResizeModalCancel);
|
|
181
|
+
field.querySelector('.js-sdfi-deletable-file__resize-validate').addEventListener('click', this.onResizeModalValidate);
|
|
182
|
+
}
|
|
163
183
|
}
|
|
164
184
|
};
|
|
165
185
|
|
|
166
|
-
|
|
186
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
167
187
|
'use strict';
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
188
|
+
var fileInputs = document.querySelectorAll('.js-sdfi-deletable-file'),
|
|
189
|
+
i;
|
|
190
|
+
|
|
191
|
+
for (i = 0; i < fileInputs.length; i += 1) {
|
|
192
|
+
window.inputSingleDeletableFile.bindEvents(fileInputs[i]);
|
|
193
|
+
}
|
|
171
194
|
});
|
|
172
195
|
|
|
173
196
|
/* Direct upload methods */
|
|
174
|
-
|
|
175
197
|
window.addEventListener('direct-upload:initialize', function (event) {
|
|
176
198
|
'use strict';
|
|
177
199
|
var target = event.target,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
200
|
+
scope = target.closest('.js-sdfi-deletable-file');
|
|
201
|
+
|
|
202
|
+
if (scope) {
|
|
203
|
+
scope.querySelector('.sdfi-deletable-file__upload-progress').style.width = '0%';
|
|
204
|
+
scope.classList.add('sdfi-deletable-file--uploading');
|
|
182
205
|
}
|
|
183
206
|
});
|
|
184
207
|
|
|
@@ -186,9 +209,9 @@ window.addEventListener('direct-upload:progress', function (event) {
|
|
|
186
209
|
'use strict';
|
|
187
210
|
var target = event.target,
|
|
188
211
|
progress = event.detail.progress,
|
|
189
|
-
|
|
190
|
-
if (
|
|
191
|
-
|
|
212
|
+
scope = target.closest('.js-sdfi-deletable-file');
|
|
213
|
+
if (scope) {
|
|
214
|
+
scope.querySelector('.sdfi-deletable-file__upload-progress').style.width = progress + '%';
|
|
192
215
|
}
|
|
193
216
|
});
|
|
194
217
|
|
|
@@ -196,11 +219,11 @@ window.addEventListener('direct-upload:error', function (event) {
|
|
|
196
219
|
'use strict';
|
|
197
220
|
var target = event.target,
|
|
198
221
|
error = event.detail.error,
|
|
199
|
-
|
|
200
|
-
if (
|
|
222
|
+
scope = target.closest('.js-sdfi-deletable-file');
|
|
223
|
+
if (scope) {
|
|
201
224
|
event.preventDefault();
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
alert(error);
|
|
225
|
+
scope.querySelector('.sdfi-deletable-file__upload-progress').style.width = '0%';
|
|
226
|
+
scope.classList.remove('sdfi-deletable-file--uploading');
|
|
227
|
+
window.alert(error);
|
|
205
228
|
}
|
|
206
229
|
});
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: simple_form_bs5_file_input
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pierre-andré Boissinot
|
|
@@ -80,6 +80,7 @@ files:
|
|
|
80
80
|
- README.md
|
|
81
81
|
- Rakefile
|
|
82
82
|
- assets/images/icon-cancel.svg
|
|
83
|
+
- assets/javascripts/polyfills/element_closest.js
|
|
83
84
|
- assets/javascripts/simple_form_bs5_file_input.js
|
|
84
85
|
- assets/stylesheets/simple_form_bs5_file_input.sass
|
|
85
86
|
- config/locales/en.yml
|