-
Notifications
You must be signed in to change notification settings - Fork 2k
/
image-upload.js
280 lines (239 loc) · 8.29 KB
/
image-upload.js
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/* Image Upload
*
*/
this.ckan.module('image-upload', function($) {
return {
/* options object can be extended using data-module-* attributes */
options: {
is_url: false,
is_upload: false,
field_upload: 'image_upload',
field_url: 'image_url',
field_clear: 'clear_upload',
field_name: 'name',
upload_label: ''
},
/* Should be changed to true if user modifies resource's name
*
* @type {Boolean}
*/
_nameIsDirty: false,
/* Initialises the module setting up elements and event listeners.
*
* Returns nothing.
*/
initialize: function () {
$.proxyAll(this, /_on/);
var options = this.options;
// firstly setup the fields
var field_upload = 'input[name="' + options.field_upload + '"]';
var field_url = 'input[name="' + options.field_url + '"]';
var field_clear = 'input[name="' + options.field_clear + '"]';
var field_name = 'input[name="' + options.field_name + '"]';
this.input = $(field_upload, this.el);
this.field_url = $(field_url, this.el).parents('.control-group');
this.field_image = this.input.parents('.control-group');
this.field_url_input = $('input', this.field_url);
this.field_name = this.el.parents('form').find(field_name);
// this is the location for the upload/link data/image label
this.label_location = $('label[for="field-image-url"]');
// determines if the resource is a data resource
this.is_data_resource = (this.options.field_url === 'url') && (this.options.field_upload === 'upload');
// Is there a clear checkbox on the form already?
var checkbox = $(field_clear, this.el);
if (checkbox.length > 0) {
checkbox.parents('.control-group').remove();
}
// Adds the hidden clear input to the form
this.field_clear = $('<input type="hidden" name="' + options.field_clear +'">')
.appendTo(this.el);
// Button to set the field to be a URL
this.button_url = $('<a href="javascript:;" class="btn">' +
'<i class="fa fa-globe"></i>' +
this._('Link') + '</a>')
.prop('title', this._('Link to a URL on the internet (you can also link to an API)'))
.on('click', this._onFromWeb)
.insertAfter(this.input);
// Button to attach local file to the form
this.button_upload = $('<a href="javascript:;" class="btn">' +
'<i class="fa fa-cloud-upload"></i>' +
this._('Upload') + '</a>')
.insertAfter(this.input);
// Button for resetting the form when there is a URL set
var removeText = this._('Remove');
$('<a href="javascript:;" class="btn btn-danger btn-remove-url">'
+ removeText + '</a>')
.prop('title', removeText)
.on('click', this._onRemove)
.insertBefore(this.field_url_input);
// Update the main label (this is displayed when no data/image has been uploaded/linked)
$('label[for="field-image-upload"]').text(options.upload_label || this._('Image'));
// Setup the file input
this.input
.on('mouseover', this._onInputMouseOver)
.on('mouseout', this._onInputMouseOut)
.on('change', this._onInputChange)
.prop('title', this._('Upload a file on your computer'))
.css('width', this.button_upload.outerWidth());
// Fields storage. Used in this.changeState
this.fields = $('<i />')
.add(this.button_upload)
.add(this.button_url)
.add(this.input)
.add(this.field_url)
.add(this.field_image);
// Disables autoName if user modifies name field
this.field_name
.on('change', this._onModifyName);
// Disables autoName if resource name already has value,
// i.e. we on edit page
if (this.field_name.val()){
this._nameIsDirty = true;
}
if (options.is_url) {
this._showOnlyFieldUrl();
this._updateUrlLabel(this._('URL'));
} else if (options.is_upload) {
this._showOnlyFieldUrl();
this.field_url_input.prop('readonly', true);
// If the data is an uploaded file, the filename will display rather than whole url of the site
var filename = this._fileNameFromUpload(this.field_url_input.val());
this.field_url_input.val(filename);
this._updateUrlLabel(this._('File'));
} else {
this._showOnlyButtons();
}
},
/* Quick way of getting just the filename from the uri of the resource data
*
* url - The url of the uploaded data file
*
* Returns String.
*/
_fileNameFromUpload: function(url) {
// If it's a local CKAN image return the entire URL.
if (/^\/base\/images/.test(url)) {
return url;
}
// remove fragment (#)
url = url.substring(0, (url.indexOf("#") === -1) ? url.length : url.indexOf("#"));
// remove query string
url = url.substring(0, (url.indexOf("?") === -1) ? url.length : url.indexOf("?"));
// extract the filename
url = url.substring(url.lastIndexOf("/") + 1, url.length);
return url; // filename
},
/* Update the `this.label_location` text
*
* If the upload/link is for a data resource, rather than an image,
* the text for label[for="field-image-url"] will be updated.
*
* label_text - The text for the label of an uploaded/linked resource
*
* Returns nothing.
*/
_updateUrlLabel: function(label_text) {
if (! this.is_data_resource) {
return;
}
this.label_location.text(label_text);
},
/* Event listener for when someone sets the field to URL mode
*
* Returns nothing.
*/
_onFromWeb: function() {
this._showOnlyFieldUrl();
this.field_url_input.focus()
.on('blur', this._onFromWebBlur);
if (this.options.is_upload) {
this.field_clear.val('true');
}
this._updateUrlLabel(this._('URL'));
},
/* Event listener for resetting the field back to the blank state
*
* Returns nothing.
*/
_onRemove: function() {
this._showOnlyButtons();
this.field_url_input.val('');
this.field_url_input.prop('readonly', false);
this.field_clear.val('true');
},
/* Event listener for when someone chooses a file to upload
*
* Returns nothing.
*/
_onInputChange: function() {
var file_name = this.input.val().split(/^C:\\fakepath\\/).pop();
this.field_url_input.val(file_name);
this.field_url_input.prop('readonly', true);
this.field_clear.val('');
this._showOnlyFieldUrl();
this._autoName(file_name);
this._updateUrlLabel(this._('File'));
},
/* Show only the buttons, hiding all others
*
* Returns nothing.
*/
_showOnlyButtons: function() {
this.fields.hide();
this.button_upload
.add(this.field_image)
.add(this.button_url)
.add(this.input)
.show();
},
/* Show only the URL field, hiding all others
*
* Returns nothing.
*/
_showOnlyFieldUrl: function() {
this.fields.hide();
this.field_url.show();
},
/* Event listener for when a user mouseovers the hidden file input
*
* Returns nothing.
*/
_onInputMouseOver: function() {
this.button_upload.addClass('hover');
},
/* Event listener for when a user mouseouts the hidden file input
*
* Returns nothing.
*/
_onInputMouseOut: function() {
this.button_upload.removeClass('hover');
},
/* Event listener for changes in resource's name by direct input from user
*
* Returns nothing
*/
_onModifyName: function() {
this._nameIsDirty = true;
},
/* Event listener for when someone loses focus of URL field
*
* Returns nothing
*/
_onFromWebBlur: function() {
var url = this.field_url_input.val().match(/([^\/]+)\/?$/)
if (url) {
this._autoName(url.pop());
}
},
/* Automatically add file name into field Name
*
* Select by attribute [name] to be on the safe side and allow to change field id
* Returns nothing
*/
_autoName: function(name) {
if (!this._nameIsDirty){
this.field_name.val(name);
}
}
};
});