1 | /*! |
||
2 | * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2015 |
||
3 | * @version 4.2.8 |
||
4 | * |
||
5 | * File input styled for Bootstrap 3.0 that utilizes HTML5 File Input's advanced |
||
6 | * features including the FileReader API. |
||
7 | * |
||
8 | * The plugin drastically enhances the HTML file input to preview multiple files on the client before |
||
9 | * upload. In addition it provides the ability to preview content of images, text, videos, audio, html, |
||
10 | * flash and other objects. It also offers the ability to upload and delete files using AJAX, and add |
||
11 | * files in batches (i.e. preview, append, or remove before upload). |
||
12 | * |
||
13 | * Author: Kartik Visweswaran |
||
14 | * Copyright: 2015, Kartik Visweswaran, Krajee.com |
||
15 | * For more JQuery plugins visit http://plugins.krajee.com |
||
16 | * For more Yii related demos visit http://demos.krajee.com |
||
17 | */ |
||
18 | (function (factory) { |
||
19 | "use strict"; |
||
20 | if (typeof define === 'function' && define.amd) { // jshint ignore:line |
||
21 | // AMD. Register as an anonymous module. |
||
22 | define(['jquery'], factory); // jshint ignore:line |
||
23 | } else { // noinspection JSUnresolvedVariable |
||
24 | if (typeof module === 'object' && module.exports) { // jshint ignore:line |
||
25 | // Node/CommonJS |
||
26 | // noinspection JSUnresolvedVariable |
||
27 | module.exports = factory(require('jquery')); // jshint ignore:line |
||
28 | } else { |
||
29 | // Browser globals |
||
30 | factory(window.jQuery); |
||
31 | } |
||
32 | } |
||
33 | }(function ($) { |
||
34 | "use strict"; |
||
35 | |||
36 | $.fn.fileinputLocales = {}; |
||
37 | |||
38 | var isIE, isEdge, handler, previewCache, getNum, hasFileAPISupport, hasDragDropSupport, hasFileUploadSupport, addCss, |
||
39 | STYLE_SETTING, OBJECT_PARAMS, DEFAULT_PREVIEW, defaultFileActionSettings, tMain1, tMain2, tPreview, tIcon, tClose, |
||
40 | tCaption, tBtnDefault, tBtnLink, tBtnBrowse, tModal, tProgress, tFooter, tActions, tActionDelete, tActionUpload, |
||
41 | tZoom, tGeneric, tHtml, tImage, tText, tVideo, tAudio, tFlash, tObject, tOther, defaultLayoutTemplates, |
||
42 | defaultPreviewTemplates, defaultPreviewTypes, defaultPreviewSettings, defaultFileTypeSettings, isEmpty, isArray, |
||
43 | isSet, getElement, uniqId, htmlEncode, replaceTags, objUrl, FileInput; |
||
44 | |||
45 | isIE = function (ver) { |
||
46 | // check for IE versions < 11 |
||
47 | if (navigator.appName !== 'Microsoft Internet Explorer') { |
||
48 | return false; |
||
49 | } |
||
50 | if (ver === 10) { |
||
51 | return new RegExp('msie\\s' + ver, 'i').test(navigator.userAgent); |
||
52 | } |
||
53 | var div = document.createElement("div"), status; |
||
54 | div.innerHTML = "<!--[if IE " + ver + "]> <i></i> <![endif]-->"; |
||
55 | status = div.getElementsByTagName("i").length; |
||
56 | document.body.appendChild(div); |
||
57 | div.parentNode.removeChild(div); |
||
58 | return status; |
||
59 | }; |
||
60 | isEdge = function () { |
||
61 | return new RegExp('Edge\/[0-9]+', 'i').test(navigator.userAgent); |
||
62 | }; |
||
63 | handler = function ($el, event, callback, skipNS) { |
||
64 | var ev = skipNS ? event : event + '.fileinput'; |
||
65 | $el.off(ev).on(ev, callback); |
||
66 | }; |
||
67 | previewCache = { |
||
68 | data: {}, |
||
69 | init: function (obj) { |
||
70 | var content = obj.initialPreview, id = obj.id; |
||
71 | if (content.length > 0 && !isArray(content)) { |
||
72 | content = content.split(obj.initialPreviewDelimiter); |
||
73 | } |
||
74 | previewCache.data[id] = { |
||
75 | content: content, |
||
76 | config: obj.initialPreviewConfig, |
||
77 | tags: obj.initialPreviewThumbTags, |
||
78 | delimiter: obj.initialPreviewDelimiter, |
||
79 | template: obj.previewGenericTemplate, |
||
80 | msg: function (n) { |
||
81 | return obj.getMsgSelected(n); |
||
82 | }, |
||
83 | initId: obj.previewInitId, |
||
84 | footer: obj.getLayoutTemplate('footer').replace(/\{progress}/g, obj.renderThumbProgress()), |
||
85 | isDelete: obj.initialPreviewShowDelete, |
||
86 | caption: obj.initialCaption, |
||
87 | actions: function (showUpload, showDelete, disabled, url, key) { |
||
88 | return obj.renderFileActions(showUpload, showDelete, disabled, url, key); |
||
89 | } |
||
90 | }; |
||
91 | }, |
||
92 | fetch: function (id) { |
||
93 | return previewCache.data[id].content.filter(function (n) { |
||
94 | return n !== null; |
||
95 | }); |
||
96 | }, |
||
97 | count: function (id, all) { |
||
98 | return !!previewCache.data[id] && !!previewCache.data[id].content ? |
||
99 | (all ? previewCache.data[id].content.length : previewCache.fetch(id).length) : 0; |
||
100 | }, |
||
101 | get: function (id, i, isDisabled) { |
||
102 | var ind = 'init_' + i, data = previewCache.data[id], config = data.config[i], |
||
103 | previewId = data.initId + '-' + ind, out, $tmp, frameClass = ' file-preview-initial'; |
||
104 | /** @namespace config.frameClass */ |
||
105 | /** @namespace config.frameAttr */ |
||
106 | isDisabled = isDisabled === undefined ? true : isDisabled; |
||
107 | if (data.content[i] === null) { |
||
108 | return ''; |
||
109 | } |
||
110 | if (!isEmpty(config) && !isEmpty(config.frameClass)) { |
||
111 | frameClass += ' ' + config.frameClass; |
||
112 | } |
||
113 | out = data.template |
||
114 | .replace(/\{previewId}/g, previewId) |
||
115 | .replace(/\{frameClass}/g, frameClass) |
||
116 | .replace(/\{fileindex}/g, ind) |
||
117 | .replace(/\{content}/g, data.content[i]) |
||
118 | .replace(/\{footer}/g, previewCache.footer(id, i, isDisabled)); |
||
119 | if (data.tags.length && data.tags[i]) { |
||
120 | out = replaceTags(out, data.tags[i]); |
||
121 | } |
||
122 | if (!isEmpty(config) && !isEmpty(config.frameAttr)) { |
||
123 | $tmp = $(document.createElement('div')).html(out); |
||
124 | $tmp.find('.file-preview-initial').attr(config.frameAttr); |
||
125 | out = $tmp.html(); |
||
126 | $tmp.remove(); |
||
127 | } |
||
128 | return out; |
||
129 | }, |
||
130 | add: function (id, content, config, tags, append) { |
||
131 | var data = $.extend(true, {}, previewCache.data[id]), index; |
||
132 | if (!isArray(content)) { |
||
133 | content = content.split(data.delimiter); |
||
134 | } |
||
135 | if (append) { |
||
136 | index = data.content.push(content) - 1; |
||
137 | data.config[index] = config; |
||
138 | data.tags[index] = tags; |
||
139 | } else { |
||
140 | index = content.length; |
||
141 | data.content = content; |
||
142 | data.config = config; |
||
143 | data.tags = tags; |
||
144 | } |
||
145 | previewCache.data[id] = data; |
||
146 | return index; |
||
147 | }, |
||
148 | set: function (id, content, config, tags, append) { |
||
149 | var data = $.extend(true, {}, previewCache.data[id]), i, chk; |
||
150 | if (!content || !content.length) { |
||
151 | return; |
||
152 | } |
||
153 | if (!isArray(content)) { |
||
154 | content = content.split(data.delimiter); |
||
155 | } |
||
156 | chk = content.filter(function (n) { |
||
157 | return n !== null; |
||
158 | }); |
||
159 | if (!chk.length) { |
||
160 | return; |
||
161 | } |
||
162 | if (data.content === undefined) { |
||
163 | data.content = []; |
||
164 | } |
||
165 | if (data.config === undefined) { |
||
166 | data.config = []; |
||
167 | } |
||
168 | if (data.tags === undefined) { |
||
169 | data.tags = []; |
||
170 | } |
||
171 | if (append) { |
||
172 | for (i = 0; i < content.length; i++) { |
||
173 | if (content[i]) { |
||
174 | data.content.push(content[i]); |
||
175 | } |
||
176 | } |
||
177 | for (i = 0; i < config.length; i++) { |
||
178 | if (config[i]) { |
||
179 | data.config.push(config[i]); |
||
180 | } |
||
181 | } |
||
182 | for (i = 0; i < tags.length; i++) { |
||
183 | if (tags[i]) { |
||
184 | data.tags.push(tags[i]); |
||
185 | } |
||
186 | } |
||
187 | } else { |
||
188 | data.content = content; |
||
189 | data.config = config; |
||
190 | data.tags = tags; |
||
191 | } |
||
192 | previewCache.data[id] = data; |
||
193 | }, |
||
194 | unset: function (id, index) { |
||
195 | var chk = previewCache.count(id); |
||
196 | if (!chk) { |
||
197 | return; |
||
198 | } |
||
199 | if (chk === 1) { |
||
200 | previewCache.data[id].content = []; |
||
201 | previewCache.data[id].config = []; |
||
202 | return; |
||
203 | } |
||
204 | previewCache.data[id].content[index] = null; |
||
205 | previewCache.data[id].config[index] = null; |
||
206 | }, |
||
207 | out: function (id) { |
||
208 | var html = '', data = previewCache.data[id], caption, len = previewCache.count(id, true); |
||
209 | if (len === 0) { |
||
210 | return {content: '', caption: ''}; |
||
211 | } |
||
212 | for (var i = 0; i < len; i++) { |
||
213 | html += previewCache.get(id, i); |
||
214 | } |
||
215 | caption = data.msg(previewCache.count(id)); |
||
216 | return {content: html, caption: caption}; |
||
217 | }, |
||
218 | footer: function (id, i, isDisabled) { |
||
219 | var data = previewCache.data[id]; |
||
220 | isDisabled = isDisabled === undefined ? true : isDisabled; |
||
221 | if (data.config.length === 0 || isEmpty(data.config[i])) { |
||
222 | return ''; |
||
223 | } |
||
224 | var config = data.config[i], |
||
225 | caption = isSet('caption', config) ? config.caption : '', |
||
226 | width = isSet('width', config) ? config.width : 'auto', |
||
227 | url = isSet('url', config) ? config.url : false, |
||
228 | key = isSet('key', config) ? config.key : null, |
||
229 | disabled = (url === false) && isDisabled, |
||
230 | actions = data.isDelete ? data.actions(false, true, disabled, url, key) : '', |
||
231 | footer = data.footer.replace(/\{actions}/g, actions); |
||
232 | return footer.replace(/\{caption}/g, caption) |
||
233 | .replace(/\{width}/g, width) |
||
234 | .replace(/\{indicator}/g, '') |
||
235 | .replace(/\{indicatorTitle}/g, ''); |
||
236 | } |
||
237 | }; |
||
238 | getNum = function (num, def) { |
||
239 | def = def || 0; |
||
240 | if (typeof num === "number") { |
||
241 | return num; |
||
242 | } |
||
243 | if (typeof num === "string") { |
||
244 | num = parseFloat(num); |
||
245 | } |
||
246 | return isNaN(num) ? def : num; |
||
247 | }; |
||
248 | hasFileAPISupport = function () { |
||
249 | return window.File && window.FileReader; |
||
250 | }; |
||
251 | hasDragDropSupport = function () { |
||
252 | var div = document.createElement('div'); |
||
253 | /** @namespace div.draggable */ |
||
254 | /** @namespace div.ondragstart */ |
||
255 | /** @namespace div.ondrop */ |
||
256 | return !isIE(9) && !isEdge() && // Fix for MS Edge drag & drop support bug |
||
257 | (div.draggable !== undefined || (div.ondragstart !== undefined && div.ondrop !== undefined)); |
||
258 | }; |
||
259 | hasFileUploadSupport = function () { |
||
260 | return hasFileAPISupport() && window.FormData; |
||
261 | }; |
||
262 | addCss = function ($el, css) { |
||
263 | $el.removeClass(css).addClass(css); |
||
264 | }; |
||
265 | STYLE_SETTING = 'style="width:{width};height:{height};"'; |
||
266 | OBJECT_PARAMS = ' <param name="controller" value="true" />\n' + |
||
267 | ' <param name="allowFullScreen" value="true" />\n' + |
||
268 | ' <param name="allowScriptAccess" value="always" />\n' + |
||
269 | ' <param name="autoPlay" value="false" />\n' + |
||
270 | ' <param name="autoStart" value="false" />\n' + |
||
271 | ' <param name="quality" value="high" />\n'; |
||
272 | DEFAULT_PREVIEW = '<div class="file-preview-other">\n' + |
||
273 | ' <span class="{previewFileIconClass}">{previewFileIcon}</span>\n' + |
||
274 | '</div>'; |
||
275 | defaultFileActionSettings = { |
||
276 | removeIcon: '<i class="glyphicon glyphicon-trash text-danger"></i>', |
||
277 | removeClass: 'btn btn-xs btn-default', |
||
278 | removeTitle: 'Remove file', |
||
279 | uploadIcon: '<i class="glyphicon glyphicon-upload text-info"></i>', |
||
280 | uploadClass: 'btn btn-xs btn-default', |
||
281 | uploadTitle: 'Upload file', |
||
282 | indicatorNew: '<i class="glyphicon glyphicon-hand-down text-warning"></i>', |
||
283 | indicatorSuccess: '<i class="glyphicon glyphicon-ok-sign text-success"></i>', |
||
284 | indicatorError: '<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>', |
||
285 | indicatorLoading: '<i class="glyphicon glyphicon-hand-up text-muted"></i>', |
||
286 | indicatorNewTitle: 'Not uploaded yet', |
||
287 | indicatorSuccessTitle: 'Uploaded', |
||
288 | indicatorErrorTitle: 'Upload Error', |
||
289 | indicatorLoadingTitle: 'Uploading ...' |
||
290 | }; |
||
291 | tMain1 = '{preview}\n' + |
||
292 | '<div class="kv-upload-progress hide"></div>\n' + |
||
293 | '<div class="input-group {class}">\n' + |
||
294 | ' {caption}\n' + |
||
295 | ' <div class="input-group-btn">\n' + |
||
296 | ' {remove}\n' + |
||
297 | ' {cancel}\n' + |
||
298 | ' {upload}\n' + |
||
299 | ' {browse}\n' + |
||
300 | ' </div>\n' + |
||
301 | '</div>'; |
||
302 | tMain2 = '{preview}\n<div class="kv-upload-progress hide"></div>\n{remove}\n{cancel}\n{upload}\n{browse}\n'; |
||
303 | tPreview = '<div class="file-preview {class}">\n' + |
||
304 | ' {close}' + |
||
305 | ' <div class="{dropClass}">\n' + |
||
306 | ' <div class="file-preview-thumbnails">\n' + |
||
307 | ' </div>\n' + |
||
308 | ' <div class="clearfix"></div>' + |
||
309 | ' <div class="file-preview-status text-center text-success"></div>\n' + |
||
310 | ' <div class="kv-fileinput-error"></div>\n' + |
||
311 | ' </div>\n' + |
||
312 | '</div>'; |
||
313 | tClose = '<div class="close fileinput-remove">×</div>\n'; |
||
314 | tIcon = '<span class="glyphicon glyphicon-file kv-caption-icon"></span>'; |
||
315 | tCaption = '<div tabindex="500" class="form-control file-caption {class}">\n' + |
||
316 | ' <div class="file-caption-name"></div>\n' + |
||
317 | '</div>\n'; |
||
318 | //noinspection HtmlUnknownAttribute |
||
319 | tBtnDefault = '<button type="{type}" tabindex="500" title="{title}" class="{css}" {status}>{icon}{label}</button>'; |
||
320 | tBtnLink = '<a href="{href}" tabindex="500" title="{title}" class="{css}" {status}>{icon}{label}</a>'; |
||
321 | tBtnBrowse = '<div tabindex="500" class="{css}" {status}>{icon}{label}</div>'; |
||
322 | tModal = '<div id="{id}" class="file-preview-detail-modal modal fade" tabindex="-1">\n' + |
||
323 | ' <div class="modal-dialog modal-lg">\n' + |
||
324 | ' <div class="modal-content">\n' + |
||
325 | ' <div class="modal-header">\n' + |
||
326 | ' <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>\n' + |
||
327 | ' <h3 class="modal-title">{heading} <small>{title}</small></h3>\n' + |
||
328 | ' </div>\n' + |
||
329 | ' <div class="modal-body">\n' + |
||
330 | ' <pre>{body}</pre>\n' + |
||
331 | ' </div>\n' + |
||
332 | ' </div>\n' + |
||
333 | ' </div>\n' + |
||
334 | '</div>'; |
||
335 | tProgress = '<div class="progress">\n' + |
||
336 | ' <div class="{class}" role="progressbar"' + |
||
337 | ' aria-valuenow="{percent}" aria-valuemin="0" aria-valuemax="100" style="width:{percent}%;">\n' + |
||
338 | ' {percent}%\n' + |
||
339 | ' </div>\n' + |
||
340 | '</div>'; |
||
341 | tFooter = '<div class="file-thumbnail-footer">\n' + |
||
342 | ' <div class="file-footer-caption" title="{caption}">{caption}</div>\n' + |
||
343 | ' {progress} {actions}\n' + |
||
344 | '</div>'; |
||
345 | tActions = '<div class="file-actions">\n' + |
||
346 | ' <div class="file-footer-buttons">\n' + |
||
347 | ' {upload}{delete}{other}' + |
||
348 | ' </div>\n' + |
||
349 | ' <div class="file-upload-indicator" title="{indicatorTitle}">{indicator}</div>\n' + |
||
350 | ' <div class="clearfix"></div>\n' + |
||
351 | '</div>'; |
||
352 | tActionDelete = '<button type="button" class="kv-file-remove {removeClass}" ' + |
||
353 | 'title="{removeTitle}" {dataUrl}{dataKey}>{removeIcon}</button>\n'; |
||
354 | tActionUpload = '<button type="button" class="kv-file-upload {uploadClass}" title="{uploadTitle}">' + |
||
355 | ' {uploadIcon}\n</button>\n'; |
||
356 | tZoom = '<button type="button" class="btn btn-default btn-xs btn-block" title="{zoomTitle}: {caption}" onclick="{dialog}">\n' + |
||
357 | ' {zoomInd}\n' + |
||
358 | '</button>\n'; |
||
359 | tGeneric = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' + |
||
360 | ' {content}\n' + |
||
361 | ' {footer}\n' + |
||
362 | '</div>\n'; |
||
363 | tHtml = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' + |
||
364 | ' <object class="file-object" data="{data}" type="{type}" width="{width}" height="{height}">\n' + |
||
365 | ' ' + DEFAULT_PREVIEW + '\n' + |
||
366 | ' </object>\n' + |
||
367 | ' {footer}\n' + |
||
368 | '</div>'; |
||
369 | tImage = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' + |
||
370 | ' <img src="{data}" class="file-preview-image" title="{caption}" alt="{caption}" ' + STYLE_SETTING + '>\n' + |
||
371 | ' {footer}\n' + |
||
372 | '</div>\n'; |
||
373 | tText = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' + |
||
374 | ' <pre class="file-preview-text" title="{caption}" ' + STYLE_SETTING + '>{data}</pre>\n' + |
||
375 | ' {zoom}\n' + |
||
376 | ' {footer}\n' + |
||
377 | '</div>'; |
||
378 | tVideo = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' + |
||
379 | ' title="{caption}" ' + STYLE_SETTING + '>\n' + |
||
380 | ' <video width="{width}" height="{height}" controls>\n' + |
||
381 | ' <source src="{data}" type="{type}">\n' + |
||
382 | ' ' + DEFAULT_PREVIEW + '\n' + |
||
383 | ' </video>\n' + |
||
384 | ' {footer}\n' + |
||
385 | '</div>\n'; |
||
386 | tAudio = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' + |
||
387 | ' title="{caption}" ' + STYLE_SETTING + '>\n' + |
||
388 | ' <audio controls>\n' + |
||
389 | ' <source src="' + '{data}' + '" type="{type}">\n' + |
||
390 | ' ' + DEFAULT_PREVIEW + '\n' + |
||
391 | ' </audio>\n' + |
||
392 | ' {footer}\n' + |
||
393 | '</div>'; |
||
394 | tFlash = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' + |
||
395 | ' title="{caption}" ' + STYLE_SETTING + '>\n' + |
||
396 | ' <object class="file-object" type="application/x-shockwave-flash" width="{width}" height="{height}" data="{data}">\n' + |
||
397 | OBJECT_PARAMS + ' ' + DEFAULT_PREVIEW + '\n' + |
||
398 | ' </object>\n' + |
||
399 | ' {footer}\n' + |
||
400 | '</div>\n'; |
||
401 | tObject = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' + |
||
402 | ' title="{caption}" ' + STYLE_SETTING + '>\n' + |
||
403 | ' <object class="file-object" data="{data}" type="{type}" width="{width}" height="{height}">\n' + |
||
404 | ' <param name="movie" value="{caption}" />\n' + |
||
405 | OBJECT_PARAMS + ' ' + DEFAULT_PREVIEW + '\n' + |
||
406 | ' </object>\n' + |
||
407 | ' {footer}\n' + |
||
408 | '</div>'; |
||
409 | tOther = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' + |
||
410 | ' title="{caption}" ' + STYLE_SETTING + '>\n' + |
||
411 | ' <div class="file-preview-other-frame">\n' + |
||
412 | ' ' + DEFAULT_PREVIEW + '\n' + |
||
413 | ' </div>\n' + |
||
414 | ' <div class="file-preview-other-footer">{footer}</div>\n' + |
||
415 | '</div>'; |
||
416 | defaultLayoutTemplates = { |
||
417 | main1: tMain1, |
||
418 | main2: tMain2, |
||
419 | preview: tPreview, |
||
420 | close: tClose, |
||
421 | zoom: tZoom, |
||
422 | icon: tIcon, |
||
423 | caption: tCaption, |
||
424 | modal: tModal, |
||
425 | progress: tProgress, |
||
426 | footer: tFooter, |
||
427 | actions: tActions, |
||
428 | actionDelete: tActionDelete, |
||
429 | actionUpload: tActionUpload, |
||
430 | btnDefault: tBtnDefault, |
||
431 | btnLink: tBtnLink, |
||
432 | btnBrowse: tBtnBrowse |
||
433 | }; |
||
434 | defaultPreviewTemplates = { |
||
435 | generic: tGeneric, |
||
436 | html: tHtml, |
||
437 | image: tImage, |
||
438 | text: tText, |
||
439 | video: tVideo, |
||
440 | audio: tAudio, |
||
441 | flash: tFlash, |
||
442 | object: tObject, |
||
443 | other: tOther |
||
444 | }; |
||
445 | defaultPreviewTypes = ['image', 'html', 'text', 'video', 'audio', 'flash', 'object']; |
||
446 | defaultPreviewSettings = { |
||
447 | image: {width: "auto", height: "160px"}, |
||
448 | html: {width: "213px", height: "160px"}, |
||
449 | text: {width: "160px", height: "136px"}, |
||
450 | video: {width: "213px", height: "160px"}, |
||
451 | audio: {width: "213px", height: "80px"}, |
||
452 | flash: {width: "213px", height: "160px"}, |
||
453 | object: {width: "160px", height: "160px"}, |
||
454 | other: {width: "160px", height: "160px"} |
||
455 | }; |
||
456 | defaultFileTypeSettings = { |
||
457 | image: function (vType, vName) { |
||
458 | return (vType !== undefined) ? vType.match('image.*') : vName.match(/\.(gif|png|jpe?g)$/i); |
||
459 | }, |
||
460 | html: function (vType, vName) { |
||
461 | return (vType !== undefined) ? vType === 'text/html' : vName.match(/\.(htm|html)$/i); |
||
462 | }, |
||
463 | text: function (vType, vName) { |
||
464 | return (vType !== undefined && vType.match('text.*')) || vName.match( |
||
465 | /\.(txt|md|csv|nfo|ini|json|php|js|css)$/i); |
||
466 | }, |
||
467 | video: function (vType, vName) { |
||
468 | return (vType !== undefined && vType.match(/\.video\/(ogg|mp4|webm|3gp)$/i)) || vName.match( |
||
469 | /\.(og?|mp4|webm|3gp)$/i); |
||
470 | }, |
||
471 | audio: function (vType, vName) { |
||
472 | return (vType !== undefined && vType.match(/\.audio\/(ogg|mp3|wav)$/i)) || vName.match(/\.(ogg|mp3|wav)$/i); |
||
473 | }, |
||
474 | flash: function (vType, vName) { |
||
475 | return (vType !== undefined && vType === 'application/x-shockwave-flash') || vName.match(/\.(swf)$/i); |
||
476 | }, |
||
477 | object: function () { |
||
478 | return true; |
||
479 | }, |
||
480 | other: function () { |
||
481 | return true; |
||
482 | } |
||
483 | }; |
||
484 | isEmpty = function (value, trim) { |
||
485 | return value === undefined || value === null || value.length === 0 || (trim && $.trim(value) === ''); |
||
486 | }; |
||
487 | isArray = function (a) { |
||
488 | return Array.isArray(a) || Object.prototype.toString.call(a) === '[object Array]'; |
||
489 | }; |
||
490 | isSet = function (needle, haystack) { |
||
491 | return (typeof haystack === 'object' && needle in haystack); |
||
492 | }; |
||
493 | getElement = function (options, param, value) { |
||
494 | return (isEmpty(options) || isEmpty(options[param])) ? value : $(options[param]); |
||
495 | }; |
||
496 | uniqId = function () { |
||
497 | return Math.round(new Date().getTime() + (Math.random() * 100)); |
||
498 | }; |
||
499 | htmlEncode = function (str) { |
||
500 | return str.replace(/&/g, '&') |
||
501 | .replace(/</g, '<') |
||
502 | .replace(/>/g, '>') |
||
503 | .replace(/"/g, '"') |
||
504 | .replace(/'/g, '''); |
||
505 | }; |
||
506 | replaceTags = function (str, tags) { |
||
507 | var out = str; |
||
508 | if (!tags) { |
||
509 | return out; |
||
510 | } |
||
511 | $.each(tags, function (key, value) { |
||
512 | if (typeof value === "function") { |
||
513 | value = value(); |
||
514 | } |
||
515 | out = out.split(key).join(value); |
||
516 | }); |
||
517 | return out; |
||
518 | }; |
||
519 | //noinspection JSUnresolvedVariable |
||
520 | objUrl = window.URL || window.webkitURL; |
||
521 | FileInput = function (element, options) { |
||
522 | var self = this; |
||
523 | self.$element = $(element); |
||
524 | if (!self.validate()) { |
||
525 | return; |
||
526 | } |
||
527 | self.isPreviewable = hasFileAPISupport(); |
||
528 | self.isIE9 = isIE(9); |
||
529 | self.isIE10 = isIE(10); |
||
530 | if (self.isPreviewable || self.isIE9) { |
||
531 | self.init(options); |
||
532 | self.listen(); |
||
533 | } else { |
||
534 | self.$element.removeClass('file-loading'); |
||
535 | } |
||
536 | }; |
||
537 | |||
538 | FileInput.prototype = { |
||
539 | constructor: FileInput, |
||
540 | validate: function () { |
||
541 | var self = this, $exception; |
||
542 | if (self.$element.attr('type') === 'file') { |
||
543 | return true; |
||
544 | } |
||
545 | $exception = '<div class="help-block alert alert-warning">' + |
||
546 | '<h4>Invalid Input Type</h4>' + |
||
547 | 'You must set an input <code>type = file</code> for <b>bootstrap-fileinput</b> plugin to initialize.' + |
||
548 | '</div>'; |
||
549 | self.$element.after($exception); |
||
550 | return false; |
||
551 | }, |
||
552 | init: function (options) { |
||
553 | var self = this, $el = self.$element, t; |
||
554 | $.each(options, function (key, value) { |
||
555 | switch (key) { |
||
556 | case 'minFileCount': |
||
557 | case 'maxFileCount': |
||
558 | case 'maxFileSize': |
||
559 | self[key] = getNum(value); |
||
560 | break; |
||
561 | default: |
||
562 | self[key] = value; |
||
563 | break; |
||
564 | } |
||
565 | }); |
||
566 | self.fileInputCleared = false; |
||
567 | self.fileBatchCompleted = true; |
||
568 | if (!self.isPreviewable) { |
||
569 | self.showPreview = false; |
||
570 | } |
||
571 | self.uploadFileAttr = !isEmpty($el.attr('name')) ? $el.attr('name') : 'file_data'; |
||
572 | self.reader = null; |
||
573 | self.formdata = {}; |
||
574 | self.clearStack(); |
||
575 | self.uploadCount = 0; |
||
576 | self.uploadStatus = {}; |
||
577 | self.uploadLog = []; |
||
578 | self.uploadAsyncCount = 0; |
||
579 | self.loadedImages = []; |
||
580 | self.totalImagesCount = 0; |
||
581 | self.ajaxRequests = []; |
||
582 | self.isError = false; |
||
583 | self.ajaxAborted = false; |
||
584 | self.cancelling = false; |
||
585 | t = self.getLayoutTemplate('progress'); |
||
586 | self.progressTemplate = t.replace('{class}', self.progressClass); |
||
587 | self.progressCompleteTemplate = t.replace('{class}', self.progressCompleteClass); |
||
588 | self.dropZoneEnabled = hasDragDropSupport() && self.dropZoneEnabled; |
||
589 | self.isDisabled = self.$element.attr('disabled') || self.$element.attr('readonly'); |
||
590 | self.isUploadable = hasFileUploadSupport() && !isEmpty(self.uploadUrl); |
||
591 | self.slug = typeof options.slugCallback === "function" ? options.slugCallback : self.slugDefault; |
||
592 | self.mainTemplate = self.showCaption ? self.getLayoutTemplate('main1') : self.getLayoutTemplate('main2'); |
||
593 | self.captionTemplate = self.getLayoutTemplate('caption'); |
||
594 | self.previewGenericTemplate = self.getPreviewTemplate('generic'); |
||
595 | if (self.resizeImage && (self.maxImageWidth || self.maxImageHeight)) { |
||
596 | self.imageCanvas = document.createElement('canvas'); |
||
597 | self.imageCanvasContext = self.imageCanvas.getContext('2d'); |
||
598 | } |
||
599 | if (isEmpty(self.$element.attr('id'))) { |
||
600 | self.$element.attr('id', uniqId()); |
||
601 | } |
||
602 | if (self.$container === undefined) { |
||
603 | self.$container = self.createContainer(); |
||
604 | } else { |
||
605 | self.refreshContainer(); |
||
606 | } |
||
607 | self.$progress = self.$container.find('.kv-upload-progress'); |
||
608 | self.$btnUpload = self.$container.find('.fileinput-upload'); |
||
609 | self.$captionContainer = getElement(options, 'elCaptionContainer', self.$container.find('.file-caption')); |
||
610 | self.$caption = getElement(options, 'elCaptionText', self.$container.find('.file-caption-name')); |
||
611 | self.$previewContainer = getElement(options, 'elPreviewContainer', self.$container.find('.file-preview')); |
||
612 | self.$preview = getElement(options, 'elPreviewImage', self.$container.find('.file-preview-thumbnails')); |
||
613 | self.$previewStatus = getElement(options, 'elPreviewStatus', self.$container.find('.file-preview-status')); |
||
614 | self.$errorContainer = getElement(options, 'elErrorContainer', |
||
615 | self.$previewContainer.find('.kv-fileinput-error')); |
||
616 | if (!isEmpty(self.msgErrorClass)) { |
||
617 | addCss(self.$errorContainer, self.msgErrorClass); |
||
618 | } |
||
619 | self.$errorContainer.hide(); |
||
620 | self.fileActionSettings = $.extend(defaultFileActionSettings, options.fileActionSettings); |
||
621 | self.previewInitId = "preview-" + uniqId(); |
||
622 | self.id = self.$element.attr('id'); |
||
623 | previewCache.init(self); |
||
624 | self.initPreview(true); |
||
625 | self.initPreviewDeletes(); |
||
626 | self.options = options; |
||
627 | self.setFileDropZoneTitle(); |
||
628 | self.$element.removeClass('file-loading'); |
||
629 | if (self.$element.attr('disabled')) { |
||
630 | self.disable(); |
||
631 | } |
||
632 | }, |
||
633 | parseError: function (jqXHR, errorThrown, fileName) { |
||
634 | var self = this, errMsg = $.trim(errorThrown + ''), |
||
635 | dot = errMsg.slice(-1) === '.' ? '' : '.', |
||
636 | text = jqXHR.responseJSON !== undefined && jqXHR.responseJSON.error !== undefined ? |
||
637 | jqXHR.responseJSON.error : jqXHR.responseText; |
||
638 | if (self.cancelling && self.msgUploadAborted) { |
||
639 | errMsg = self.msgUploadAborted; |
||
640 | } |
||
641 | if (self.showAjaxErrorDetails && text) { |
||
642 | text = $.trim(text.replace(/\n\s*\n/g, '\n')); |
||
643 | text = text.length > 0 ? '<pre>' + text + '</pre>' : ''; |
||
644 | errMsg += dot + text; |
||
645 | } else { |
||
646 | errMsg += dot; |
||
647 | } |
||
648 | self.cancelling = false; |
||
649 | return fileName ? '<b>' + fileName + ': </b>' + errMsg : errMsg; |
||
650 | }, |
||
651 | raise: function (event, params) { |
||
652 | var self = this, e = $.Event(event); |
||
653 | if (params !== undefined) { |
||
654 | self.$element.trigger(e, params); |
||
655 | } else { |
||
656 | self.$element.trigger(e); |
||
657 | } |
||
658 | if (e.isDefaultPrevented()) { |
||
659 | return false; |
||
660 | } |
||
661 | if (!e.result) { |
||
662 | return e.result; |
||
663 | } |
||
664 | switch (event) { |
||
665 | // ignore these events |
||
666 | case 'filebatchuploadcomplete': |
||
667 | case 'filebatchuploadsuccess': |
||
668 | case 'fileuploaded': |
||
669 | case 'fileclear': |
||
670 | case 'filecleared': |
||
671 | case 'filereset': |
||
672 | case 'fileerror': |
||
673 | case 'filefoldererror': |
||
674 | case 'fileuploaderror': |
||
675 | case 'filebatchuploaderror': |
||
676 | case 'filedeleteerror': |
||
677 | case 'filecustomerror': |
||
678 | case 'filesuccessremove': |
||
679 | break; |
||
680 | // receive data response via `filecustomerror` event` |
||
681 | default: |
||
682 | self.ajaxAborted = e.result; |
||
683 | break; |
||
684 | } |
||
685 | return true; |
||
686 | }, |
||
687 | getLayoutTemplate: function (t) { |
||
688 | var self = this, |
||
689 | template = isSet(t, self.layoutTemplates) ? self.layoutTemplates[t] : defaultLayoutTemplates[t]; |
||
690 | if (isEmpty(self.customLayoutTags)) { |
||
691 | return template; |
||
692 | } |
||
693 | return replaceTags(template, self.customLayoutTags); |
||
694 | }, |
||
695 | getPreviewTemplate: function (t) { |
||
696 | var self = this, |
||
697 | template = isSet(t, self.previewTemplates) ? self.previewTemplates[t] : defaultPreviewTemplates[t]; |
||
698 | if (isEmpty(self.customPreviewTags)) { |
||
699 | return template; |
||
700 | } |
||
701 | return replaceTags(template, self.customPreviewTags); |
||
702 | }, |
||
703 | parseFilePreviewIcon: function (content, fname) { |
||
704 | var self = this, ext, icn = self.previewFileIcon; |
||
705 | if (fname && fname.indexOf('.') > -1) { |
||
706 | ext = fname.split('.').pop(); |
||
707 | if (self.previewFileIconSettings && self.previewFileIconSettings[ext]) { |
||
708 | icn = self.previewFileIconSettings[ext]; |
||
709 | } |
||
710 | if (self.previewFileExtSettings) { |
||
711 | $.each(self.previewFileExtSettings, function (key, func) { |
||
712 | if (self.previewFileIconSettings[key] && func(ext)) { |
||
713 | icn = self.previewFileIconSettings[key]; |
||
714 | } |
||
715 | }); |
||
716 | } |
||
717 | } |
||
718 | if (content.indexOf('{previewFileIcon}') > -1) { |
||
719 | return content.replace(/\{previewFileIconClass}/g, self.previewFileIconClass).replace( |
||
720 | /\{previewFileIcon}/g, icn); |
||
721 | } |
||
722 | return content; |
||
723 | }, |
||
724 | getOutData: function (jqXHR, responseData, filesData) { |
||
725 | var self = this; |
||
726 | jqXHR = jqXHR || {}; |
||
727 | responseData = responseData || {}; |
||
728 | filesData = filesData || self.filestack.slice(0) || {}; |
||
729 | return { |
||
730 | form: self.formdata, |
||
731 | files: filesData, |
||
732 | filenames: self.filenames, |
||
733 | extra: self.getExtraData(), |
||
734 | response: responseData, |
||
735 | reader: self.reader, |
||
736 | jqXHR: jqXHR |
||
737 | }; |
||
738 | }, |
||
739 | listen: function () { |
||
740 | var self = this, $el = self.$element, $cap = self.$captionContainer, $btnFile = self.$btnFile, |
||
741 | $form = $el.closest('form'), $cont = self.$container; |
||
742 | handler($el, 'change', $.proxy(self.change, self)); |
||
743 | handler($btnFile, 'click', function () { |
||
744 | self.raise('filebrowse'); |
||
745 | if (self.isError && !self.isUploadable) { |
||
746 | self.clear(); |
||
747 | } |
||
748 | $cap.focus(); |
||
749 | }); |
||
750 | handler($form, 'reset', $.proxy(self.reset, self)); |
||
751 | handler($cont.find('.fileinput-remove:not([disabled])'), 'click', $.proxy(self.clear, self)); |
||
752 | handler($cont.find('.fileinput-cancel'), 'click', $.proxy(self.cancel, self)); |
||
753 | if (self.isUploadable && self.dropZoneEnabled && self.showPreview) { |
||
754 | self.initDragDrop(); |
||
755 | } |
||
756 | if (!self.isUploadable) { |
||
757 | handler($form, 'submit', $.proxy(self.submitForm, self)); |
||
758 | } |
||
759 | handler(self.$container.find('.fileinput-upload'), 'click', function (e) { |
||
760 | var $btn = $(this), $form, isEnabled = !$btn.hasClass('disabled') && isEmpty($btn.attr('disabled')); |
||
761 | if (!self.isUploadable) { |
||
762 | if (isEnabled && $btn.attr('type') !== 'submit') { |
||
763 | $form = $btn.closest('form'); |
||
764 | // downgrade to normal form submit if possible |
||
765 | if ($form.length) { |
||
766 | $form.trigger('submit'); |
||
767 | } |
||
768 | e.preventDefault(); |
||
769 | } |
||
770 | return; |
||
771 | } |
||
772 | e.preventDefault(); |
||
773 | if (isEnabled) { |
||
774 | self.upload(); |
||
775 | } |
||
776 | }); |
||
777 | }, |
||
778 | submitForm: function () { |
||
779 | var self = this, $el = self.$element, files = $el.get(0).files; |
||
780 | if (files && self.minFileCount > 0 && self.getFileCount(files.length) < self.minFileCount) { |
||
781 | self.noFilesError({}); |
||
782 | return false; |
||
783 | } |
||
784 | return !self.abort({}); |
||
785 | }, |
||
786 | abort: function (params) { |
||
787 | var self = this, data; |
||
788 | if (self.ajaxAborted && typeof self.ajaxAborted === "object" && self.ajaxAborted.message !== undefined) { |
||
789 | data = $.extend(self.getOutData(), params); |
||
790 | data.abortData = self.ajaxAborted.data || {}; |
||
791 | data.abortMessage = self.ajaxAborted.message; |
||
792 | self.cancel(); |
||
793 | self.setProgress(100); |
||
794 | self.showUploadError(self.ajaxAborted.message, data, 'filecustomerror'); |
||
795 | return true; |
||
796 | } |
||
797 | return false; |
||
798 | }, |
||
799 | noFilesError: function (params) { |
||
800 | var self = this, label = self.minFileCount > 1 ? self.filePlural : self.fileSingle, |
||
801 | msg = self.msgFilesTooLess.replace('{n}', self.minFileCount).replace('{files}', label), |
||
802 | $error = self.$errorContainer; |
||
803 | self.addError(msg); |
||
804 | self.isError = true; |
||
805 | self.updateFileDetails(0); |
||
806 | $error.fadeIn(800); |
||
807 | self.raise('fileerror', [params]); |
||
808 | self.clearFileInput(); |
||
809 | addCss(self.$container, 'has-error'); |
||
810 | }, |
||
811 | setProgress: function (p, $el) { |
||
812 | var self = this, pct = Math.min(p, 100), |
||
813 | template = pct < 100 ? self.progressTemplate : self.progressCompleteTemplate; |
||
814 | $el = $el || self.$progress; |
||
815 | if (!isEmpty(template)) { |
||
816 | $el.html(template.replace(/\{percent}/g, pct)); |
||
817 | } |
||
818 | }, |
||
819 | lock: function () { |
||
820 | var self = this; |
||
821 | self.resetErrors(); |
||
822 | self.disable(); |
||
823 | if (self.showRemove) { |
||
824 | addCss(self.$container.find('.fileinput-remove'), 'hide'); |
||
825 | } |
||
826 | if (self.showCancel) { |
||
827 | self.$container.find('.fileinput-cancel').removeClass('hide'); |
||
828 | } |
||
829 | self.raise('filelock', [self.filestack, self.getExtraData()]); |
||
830 | }, |
||
831 | unlock: function (reset) { |
||
832 | var self = this; |
||
833 | if (reset === undefined) { |
||
834 | reset = true; |
||
835 | } |
||
836 | self.enable(); |
||
837 | if (self.showCancel) { |
||
838 | addCss(self.$container.find('.fileinput-cancel'), 'hide'); |
||
839 | } |
||
840 | if (self.showRemove) { |
||
841 | self.$container.find('.fileinput-remove').removeClass('hide'); |
||
842 | } |
||
843 | if (reset) { |
||
844 | self.resetFileStack(); |
||
845 | } |
||
846 | self.raise('fileunlock', [self.filestack, self.getExtraData()]); |
||
847 | }, |
||
848 | resetFileStack: function () { |
||
849 | var self = this, i = 0, newstack = [], newnames = []; |
||
850 | self.getThumbs().each(function () { |
||
851 | var $thumb = $(this), ind = $thumb.attr('data-fileindex'), |
||
852 | file = self.filestack[ind]; |
||
853 | if (ind === -1) { |
||
854 | return; |
||
855 | } |
||
856 | if (file !== undefined) { |
||
857 | newstack[i] = file; |
||
858 | newnames[i] = self.getFileName(file); |
||
859 | $thumb.attr({ |
||
860 | 'id': self.previewInitId + '-' + i, |
||
861 | 'data-fileindex': i |
||
862 | }); |
||
863 | i++; |
||
864 | } else { |
||
865 | $thumb.attr({ |
||
866 | 'id': 'uploaded-' + uniqId(), |
||
867 | 'data-fileindex': '-1' |
||
868 | }); |
||
869 | } |
||
870 | }); |
||
871 | self.filestack = newstack; |
||
872 | self.filenames = newnames; |
||
873 | }, |
||
874 | destroy: function () { |
||
875 | var self = this, $cont = self.$container; |
||
876 | $cont.find('.file-drop-zone').off(); |
||
877 | self.$element.insertBefore($cont).off('.fileinput').removeData(); |
||
878 | $cont.off().remove(); |
||
879 | }, |
||
880 | refresh: function (options) { |
||
881 | var self = this, $el = self.$element; |
||
882 | options = options ? $.extend(self.options, options) : self.options; |
||
883 | self.destroy(); |
||
884 | $el.fileinput(options); |
||
885 | if ($el.val()) { |
||
886 | $el.trigger('change.fileinput'); |
||
887 | } |
||
888 | }, |
||
889 | initDragDrop: function () { |
||
890 | var self = this, $zone = self.$container.find('.file-drop-zone'), |
||
891 | allEvents = 'dragenter.fileinput dragover.fileinput drop.fileinput'; |
||
892 | handler($zone, 'dragenter.fileinput dragover.fileinput', function (e) { |
||
893 | var hasFiles = $.inArray('Files', e.originalEvent.dataTransfer.types) > -1; |
||
894 | e.stopPropagation(); |
||
895 | e.preventDefault(); |
||
896 | if (self.isDisabled || !hasFiles) { |
||
897 | e.originalEvent.dataTransfer.effectAllowed = 'none'; |
||
898 | e.originalEvent.dataTransfer.dropEffect = 'none'; |
||
899 | return; |
||
900 | } |
||
901 | addCss($(this), 'file-highlighted'); |
||
902 | }, true); |
||
903 | handler($zone, 'dragleave', function (e) { |
||
904 | e.stopPropagation(); |
||
905 | e.preventDefault(); |
||
906 | if (self.isDisabled) { |
||
907 | return; |
||
908 | } |
||
909 | $(this).removeClass('file-highlighted'); |
||
910 | }); |
||
911 | handler($zone, 'drop', function (e) { |
||
912 | e.preventDefault(); |
||
913 | /** @namespace e.originalEvent.dataTransfer */ |
||
914 | if (self.isDisabled || isEmpty(e.originalEvent.dataTransfer.files)) { |
||
915 | return; |
||
916 | } |
||
917 | self.change(e, 'dragdrop'); |
||
918 | $(this).removeClass('file-highlighted'); |
||
919 | }); |
||
920 | handler($(document), allEvents, function (e) { |
||
921 | e.stopPropagation(); |
||
922 | e.preventDefault(); |
||
923 | }, true); |
||
924 | }, |
||
925 | setFileDropZoneTitle: function () { |
||
926 | var self = this, $zone = self.$container.find('.file-drop-zone'); |
||
927 | $zone.find('.' + self.dropZoneTitleClass).remove(); |
||
928 | if (!self.isUploadable || !self.showPreview || $zone.length === 0 || self.getFileStack().length > 0 || !self.dropZoneEnabled) { |
||
929 | return; |
||
930 | } |
||
931 | if ($zone.find('.file-preview-frame').length === 0 && isEmpty(self.defaultPreviewContent)) { |
||
932 | $zone.prepend('<div class="' + self.dropZoneTitleClass + '">' + self.dropZoneTitle + '</div>'); |
||
933 | } |
||
934 | self.$container.removeClass('file-input-new'); |
||
935 | addCss(self.$container, 'file-input-ajax-new'); |
||
936 | }, |
||
937 | errorsExist: function () { |
||
938 | var self = this, $err; |
||
939 | if (self.$errorContainer.find('li').length) { |
||
940 | return true; |
||
941 | } |
||
942 | $err = $(document.createElement('div')).html(self.$errorContainer.html()); |
||
943 | $err.find('span.kv-error-close').remove(); |
||
944 | $err.find('ul').remove(); |
||
945 | return $.trim($err.text()).length ? true : false; |
||
946 | }, |
||
947 | getMsgSelected: function (n) { |
||
948 | var self = this, strFiles = n === 1 ? self.fileSingle : self.filePlural; |
||
949 | return self.msgSelected.replace('{n}', n).replace('{files}', strFiles); |
||
950 | }, |
||
951 | renderThumbProgress: function () { |
||
952 | return '<div class="file-thumb-progress hide">' + this.progressTemplate.replace(/\{percent}/g, |
||
953 | '0') + '</div>'; |
||
954 | }, |
||
955 | renderFileFooter: function (caption, width) { |
||
956 | var self = this, config = self.fileActionSettings, footer, out, template = self.getLayoutTemplate('footer'); |
||
957 | if (self.isUploadable) { |
||
958 | footer = template.replace(/\{actions}/g, self.renderFileActions(true, true, false, false, false)); |
||
959 | out = footer.replace(/\{caption}/g, caption) |
||
960 | .replace(/\{width}/g, width) |
||
961 | .replace(/\{progress}/g, self.renderThumbProgress()) |
||
962 | .replace(/\{indicator}/g, config.indicatorNew) |
||
963 | .replace(/\{indicatorTitle}/g, config.indicatorNewTitle); |
||
964 | } else { |
||
965 | out = template.replace(/\{actions}/g, '') |
||
966 | .replace(/\{caption}/g, caption) |
||
967 | .replace(/\{progress}/g, '') |
||
968 | .replace(/\{width}/g, width) |
||
969 | .replace(/\{indicator}/g, '') |
||
970 | .replace(/\{indicatorTitle}/g, ''); |
||
971 | } |
||
972 | out = replaceTags(out, self.previewThumbTags); |
||
973 | return out; |
||
974 | }, |
||
975 | renderFileActions: function (showUpload, showDelete, disabled, url, key) { |
||
976 | if (!showUpload && !showDelete) { |
||
977 | return ''; |
||
978 | } |
||
979 | var self = this, |
||
980 | vUrl = url === false ? '' : ' data-url="' + url + '"', |
||
981 | vKey = key === false ? '' : ' data-key="' + key + '"', |
||
982 | btnDelete = self.getLayoutTemplate('actionDelete'), |
||
983 | btnUpload = '', |
||
984 | template = self.getLayoutTemplate('actions'), |
||
985 | otherButtons = self.otherActionButtons.replace(/\{dataKey}/g, vKey), |
||
986 | config = self.fileActionSettings, |
||
987 | removeClass = disabled ? config.removeClass + ' disabled' : config.removeClass; |
||
988 | btnDelete = btnDelete |
||
989 | .replace(/\{removeClass}/g, removeClass) |
||
990 | .replace(/\{removeIcon}/g, config.removeIcon) |
||
991 | .replace(/\{removeTitle}/g, config.removeTitle) |
||
992 | .replace(/\{dataUrl}/g, vUrl) |
||
993 | .replace(/\{dataKey}/g, vKey); |
||
994 | if (showUpload) { |
||
995 | btnUpload = self.getLayoutTemplate('actionUpload') |
||
996 | .replace(/\{uploadClass}/g, config.uploadClass) |
||
997 | .replace(/\{uploadIcon}/g, config.uploadIcon) |
||
998 | .replace(/\{uploadTitle}/g, config.uploadTitle); |
||
999 | } |
||
1000 | return template |
||
1001 | .replace(/\{delete}/g, btnDelete) |
||
1002 | .replace(/\{upload}/g, btnUpload) |
||
1003 | .replace(/\{other}/g, otherButtons); |
||
1004 | }, |
||
1005 | setThumbStatus: function ($thumb, status) { |
||
1006 | var self = this; |
||
1007 | if (!self.showPreview) { |
||
1008 | return; |
||
1009 | } |
||
1010 | var icon = 'indicator' + status, msg = icon + 'Title', |
||
1011 | css = 'file-preview-' + status.toLowerCase(), |
||
1012 | $indicator = $thumb.find('.file-upload-indicator'), |
||
1013 | config = self.fileActionSettings; |
||
1014 | $thumb.removeClass('file-preview-success file-preview-error file-preview-loading'); |
||
1015 | if (status === 'Error') { |
||
1016 | $thumb.find('.kv-file-upload').attr('disabled', true); |
||
1017 | } |
||
1018 | $indicator.html(config[icon]); |
||
1019 | $indicator.attr('title', config[msg]); |
||
1020 | $thumb.addClass(css); |
||
1021 | }, |
||
1022 | clearPreview: function () { |
||
1023 | var self = this, $thumbs = !self.showUploadedThumbs ? self.$preview.find('.file-preview-frame') : |
||
1024 | self.$preview.find('.file-preview-frame:not(.file-preview-success)'); |
||
1025 | $thumbs.remove(); |
||
1026 | if (!self.$preview.find('.file-preview-frame').length || !self.showPreview) { |
||
1027 | self.resetUpload(); |
||
1028 | } |
||
1029 | self.validateDefaultPreview(); |
||
1030 | }, |
||
1031 | initPreview: function (isInit) { |
||
1032 | var self = this, cap = self.initialCaption || '', out; |
||
1033 | if (!previewCache.count(self.id)) { |
||
1034 | self.clearPreview(); |
||
1035 | if (isInit) { |
||
1036 | self.setCaption(cap); |
||
1037 | } else { |
||
1038 | self.initCaption(); |
||
1039 | } |
||
1040 | return; |
||
1041 | } |
||
1042 | out = previewCache.out(self.id); |
||
1043 | cap = isInit && self.initialCaption ? self.initialCaption : out.caption; |
||
1044 | self.$preview.html(out.content); |
||
1045 | self.setCaption(cap); |
||
1046 | if (!isEmpty(out.content)) { |
||
1047 | self.$container.removeClass('file-input-new'); |
||
1048 | } |
||
1049 | }, |
||
1050 | initPreviewDeletes: function () { |
||
1051 | var self = this, deleteExtraData = self.deleteExtraData || {}, |
||
1052 | resetProgress = function () { |
||
1053 | var hasFiles = self.isUploadable ? previewCache.count(self.id) : self.$element.get(0).files.length; |
||
1054 | if (self.$preview.find('.kv-file-remove').length === 0 && !hasFiles) { |
||
1055 | self.reset(); |
||
1056 | self.initialCaption = ''; |
||
1057 | } |
||
1058 | }; |
||
1059 | |||
1060 | self.$preview.find('.kv-file-remove').each(function () { |
||
1061 | var $el = $(this), vUrl = $el.data('url') || self.deleteUrl, vKey = $el.data('key'); |
||
1062 | if (isEmpty(vUrl) || vKey === undefined) { |
||
1063 | return; |
||
1064 | } |
||
1065 | var $frame = $el.closest('.file-preview-frame'), cache = previewCache.data[self.id], |
||
1066 | settings, params, index = $frame.data('fileindex'), config, extraData; |
||
1067 | index = parseInt(index.replace('init_', '')); |
||
1068 | config = isEmpty(cache.config) && isEmpty(cache.config[index]) ? null : cache.config[index]; |
||
1069 | extraData = isEmpty(config) || isEmpty(config.extra) ? deleteExtraData : config.extra; |
||
1070 | if (typeof extraData === "function") { |
||
1071 | extraData = extraData(); |
||
1072 | } |
||
1073 | params = {id: $el.attr('id'), key: vKey, extra: extraData}; |
||
1074 | settings = $.extend({ |
||
1075 | url: vUrl, |
||
1076 | type: 'POST', |
||
1077 | dataType: 'json', |
||
1078 | data: $.extend({key: vKey}, extraData), |
||
1079 | beforeSend: function (jqXHR) { |
||
1080 | self.ajaxAborted = false; |
||
1081 | self.raise('filepredelete', [vKey, jqXHR, extraData]); |
||
1082 | if (self.ajaxAborted) { |
||
1083 | jqXHR.abort(); |
||
1084 | } else { |
||
1085 | addCss($frame, 'file-uploading'); |
||
1086 | addCss($el, 'disabled'); |
||
1087 | } |
||
1088 | }, |
||
1089 | success: function (data, textStatus, jqXHR) { |
||
1090 | var n, cap; |
||
1091 | if (isEmpty(data) || isEmpty(data.error)) { |
||
1092 | previewCache.unset(self.id, index); |
||
1093 | n = previewCache.count(self.id); |
||
1094 | cap = n > 0 ? self.getMsgSelected(n) : ''; |
||
1095 | self.raise('filedeleted', [vKey, jqXHR, extraData]); |
||
1096 | self.setCaption(cap); |
||
1097 | } else { |
||
1098 | params.jqXHR = jqXHR; |
||
1099 | params.response = data; |
||
1100 | self.showError(data.error, params, 'filedeleteerror'); |
||
1101 | $frame.removeClass('file-uploading'); |
||
1102 | $el.removeClass('disabled'); |
||
1103 | resetProgress(); |
||
1104 | return; |
||
1105 | } |
||
1106 | $frame.removeClass('file-uploading').addClass('file-deleted'); |
||
1107 | $frame.fadeOut('slow', function () { |
||
1108 | self.clearObjects($frame); |
||
1109 | $frame.remove(); |
||
1110 | resetProgress(); |
||
1111 | if (!n && self.getFileStack().length === 0) { |
||
1112 | self.setCaption(''); |
||
1113 | self.reset(); |
||
1114 | } |
||
1115 | }); |
||
1116 | }, |
||
1117 | error: function (jqXHR, textStatus, errorThrown) { |
||
1118 | var errMsg = self.parseError(jqXHR, errorThrown); |
||
1119 | params.jqXHR = jqXHR; |
||
1120 | params.response = {}; |
||
1121 | self.showError(errMsg, params, 'filedeleteerror'); |
||
1122 | $frame.removeClass('file-uploading'); |
||
1123 | resetProgress(); |
||
1124 | } |
||
1125 | }, self.ajaxDeleteSettings); |
||
1126 | handler($el, 'click', function () { |
||
1127 | if (!self.validateMinCount()) { |
||
1128 | return false; |
||
1129 | } |
||
1130 | $.ajax(settings); |
||
1131 | }); |
||
1132 | }); |
||
1133 | }, |
||
1134 | clearObjects: function ($el) { |
||
1135 | $el.find('video audio').each(function () { |
||
1136 | this.pause(); |
||
1137 | $(this).remove(); |
||
1138 | }); |
||
1139 | $el.find('img object div').each(function () { |
||
1140 | $(this).remove(); |
||
1141 | }); |
||
1142 | }, |
||
1143 | clearFileInput: function () { |
||
1144 | var self = this, $el = self.$element, $srcFrm, $tmpFrm, $tmpEl; |
||
1145 | if (isEmpty($el.val())) { |
||
1146 | return; |
||
1147 | } |
||
1148 | // Fix for IE ver < 11, that does not clear file inputs |
||
1149 | // Requires a sequence of steps to prevent IE crashing but |
||
1150 | // still allow clearing of the file input. |
||
1151 | if (self.isIE9 || self.isIE10) { |
||
1152 | $srcFrm = $el.closest('form'); |
||
1153 | $tmpFrm = $(document.createElement('form')); |
||
1154 | $tmpEl = $(document.createElement('div')); |
||
1155 | $el.before($tmpEl); |
||
1156 | if ($srcFrm.length) { |
||
1157 | $srcFrm.after($tmpFrm); |
||
1158 | } else { |
||
1159 | $tmpEl.after($tmpFrm); |
||
1160 | } |
||
1161 | $tmpFrm.append($el).trigger('reset'); |
||
1162 | $tmpEl.before($el).remove(); |
||
1163 | $tmpFrm.remove(); |
||
1164 | } else { // normal input clear behavior for other sane browsers |
||
1165 | $el.val(''); |
||
1166 | } |
||
1167 | self.fileInputCleared = true; |
||
1168 | }, |
||
1169 | resetUpload: function () { |
||
1170 | var self = this; |
||
1171 | self.uploadCache = {content: [], config: [], tags: [], append: true}; |
||
1172 | self.uploadCount = 0; |
||
1173 | self.uploadStatus = {}; |
||
1174 | self.uploadLog = []; |
||
1175 | self.uploadAsyncCount = 0; |
||
1176 | self.loadedImages = []; |
||
1177 | self.totalImagesCount = 0; |
||
1178 | self.$btnUpload.removeAttr('disabled'); |
||
1179 | self.setProgress(0); |
||
1180 | addCss(self.$progress, 'hide'); |
||
1181 | self.resetErrors(false); |
||
1182 | self.ajaxAborted = false; |
||
1183 | self.ajaxRequests = []; |
||
1184 | self.resetCanvas(); |
||
1185 | }, |
||
1186 | resetCanvas: function () { |
||
1187 | var self = this; |
||
1188 | if (self.canvas && self.imageCanvasContext) { |
||
1189 | self.imageCanvasContext.clearRect(0, 0, self.canvas.width, self.canvas.height); |
||
1190 | } |
||
1191 | }, |
||
1192 | cancel: function () { |
||
1193 | var self = this, xhr = self.ajaxRequests, len = xhr.length, i; |
||
1194 | if (len > 0) { |
||
1195 | for (i = 0; i < len; i += 1) { |
||
1196 | self.cancelling = true; |
||
1197 | xhr[i].abort(); |
||
1198 | } |
||
1199 | } |
||
1200 | self.getThumbs().each(function () { |
||
1201 | var $thumb = $(this), ind = $thumb.attr('data-fileindex'); |
||
1202 | $thumb.removeClass('file-uploading'); |
||
1203 | if (self.filestack[ind] !== undefined) { |
||
1204 | $thumb.find('.kv-file-upload').removeClass('disabled').removeAttr('disabled'); |
||
1205 | $thumb.find('.kv-file-remove').removeClass('disabled').removeAttr('disabled'); |
||
1206 | } |
||
1207 | self.unlock(); |
||
1208 | }); |
||
1209 | }, |
||
1210 | cleanMemory: function ($thumb) { |
||
1211 | var data = $thumb.is('img') ? $thumb.attr('src') : $thumb.find('source').attr('src'); |
||
1212 | /** @namespace objUrl.revokeObjectURL */ |
||
1213 | objUrl.revokeObjectURL(data); |
||
1214 | }, |
||
1215 | hasInitialPreview: function () { |
||
1216 | var self = this; |
||
1217 | return !self.overwriteInitial && previewCache.count(self.id); |
||
1218 | }, |
||
1219 | clear: function () { |
||
1220 | var self = this, cap; |
||
1221 | self.$btnUpload.removeAttr('disabled'); |
||
1222 | self.getThumbs().find('video,audio,img').each(function () { |
||
1223 | self.cleanMemory($(this)); |
||
1224 | }); |
||
1225 | self.resetUpload(); |
||
1226 | self.clearStack(); |
||
1227 | self.clearFileInput(); |
||
1228 | self.resetErrors(true); |
||
1229 | self.raise('fileclear'); |
||
1230 | if (self.hasInitialPreview()) { |
||
1231 | self.showFileIcon(); |
||
1232 | self.resetPreview(); |
||
1233 | self.initPreviewDeletes(); |
||
1234 | self.$container.removeClass('file-input-new'); |
||
1235 | } else { |
||
1236 | self.getThumbs().each(function () { |
||
1237 | self.clearObjects($(this)); |
||
1238 | }); |
||
1239 | if (self.isUploadable) { |
||
1240 | previewCache.data[self.id] = {}; |
||
1241 | } |
||
1242 | self.$preview.html(''); |
||
1243 | cap = (!self.overwriteInitial && self.initialCaption.length > 0) ? self.initialCaption : ''; |
||
1244 | self.setCaption(cap); |
||
1245 | self.$caption.attr('title', ''); |
||
1246 | addCss(self.$container, 'file-input-new'); |
||
1247 | self.validateDefaultPreview(); |
||
1248 | } |
||
1249 | if (self.$container.find('.file-preview-frame').length === 0) { |
||
1250 | if (!self.initCaption()) { |
||
1251 | self.$captionContainer.find('.kv-caption-icon').hide(); |
||
1252 | } |
||
1253 | } |
||
1254 | self.hideFileIcon(); |
||
1255 | self.raise('filecleared'); |
||
1256 | self.$captionContainer.focus(); |
||
1257 | self.setFileDropZoneTitle(); |
||
1258 | }, |
||
1259 | resetPreview: function () { |
||
1260 | var self = this, out, cap; |
||
1261 | if (previewCache.count(self.id)) { |
||
1262 | out = previewCache.out(self.id); |
||
1263 | self.$preview.html(out.content); |
||
1264 | cap = self.initialCaption ? self.initialCaption : out.caption; |
||
1265 | self.setCaption(cap); |
||
1266 | } else { |
||
1267 | self.clearPreview(); |
||
1268 | self.initCaption(); |
||
1269 | } |
||
1270 | }, |
||
1271 | clearDefaultPreview: function () { |
||
1272 | var self = this; |
||
1273 | self.$preview.find('.file-default-preview').remove(); |
||
1274 | }, |
||
1275 | validateDefaultPreview: function () { |
||
1276 | var self = this; |
||
1277 | if (!self.showPreview || isEmpty(self.defaultPreviewContent)) { |
||
1278 | return; |
||
1279 | } |
||
1280 | self.$preview.html('<div class="file-default-preview">' + self.defaultPreviewContent + '</div>'); |
||
1281 | self.$container.removeClass('file-input-new'); |
||
1282 | }, |
||
1283 | resetPreviewThumbs: function (isAjax) { |
||
1284 | var self = this, out; |
||
1285 | if (isAjax) { |
||
1286 | self.clearPreview(); |
||
1287 | self.clearStack(); |
||
1288 | return; |
||
1289 | } |
||
1290 | if (self.hasInitialPreview()) { |
||
1291 | out = previewCache.out(self.id); |
||
1292 | self.$preview.html(out.content); |
||
1293 | self.setCaption(out.caption); |
||
1294 | self.initPreviewDeletes(); |
||
1295 | } else { |
||
1296 | self.clearPreview(); |
||
1297 | } |
||
1298 | }, |
||
1299 | reset: function () { |
||
1300 | var self = this; |
||
1301 | self.resetPreview(); |
||
1302 | self.$container.find('.fileinput-filename').text(''); |
||
1303 | self.raise('filereset'); |
||
1304 | addCss(self.$container, 'file-input-new'); |
||
1305 | if (self.$preview.find('.file-preview-frame').length || self.isUploadable && self.dropZoneEnabled) { |
||
1306 | self.$container.removeClass('file-input-new'); |
||
1307 | } |
||
1308 | self.setFileDropZoneTitle(); |
||
1309 | self.clearStack(); |
||
1310 | self.formdata = {}; |
||
1311 | }, |
||
1312 | disable: function () { |
||
1313 | var self = this; |
||
1314 | self.isDisabled = true; |
||
1315 | self.raise('filedisabled'); |
||
1316 | self.$element.attr('disabled', 'disabled'); |
||
1317 | self.$container.find(".kv-fileinput-caption").addClass("file-caption-disabled"); |
||
1318 | self.$container.find(".btn-file, .fileinput-remove, .fileinput-upload, .file-preview-frame button").attr( |
||
1319 | "disabled", |
||
1320 | true); |
||
1321 | self.initDragDrop(); |
||
1322 | }, |
||
1323 | enable: function () { |
||
1324 | var self = this; |
||
1325 | self.isDisabled = false; |
||
1326 | self.raise('fileenabled'); |
||
1327 | self.$element.removeAttr('disabled'); |
||
1328 | self.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled"); |
||
1329 | self.$container.find( |
||
1330 | ".btn-file, .fileinput-remove, .fileinput-upload, .file-preview-frame button").removeAttr("disabled"); |
||
1331 | self.initDragDrop(); |
||
1332 | }, |
||
1333 | getThumbs: function (css) { |
||
1334 | css = css || ''; |
||
1335 | return this.$preview.find('.file-preview-frame:not(.file-preview-initial)' + css); |
||
1336 | }, |
||
1337 | getExtraData: function (previewId, index) { |
||
1338 | var self = this, data = self.uploadExtraData; |
||
1339 | if (typeof self.uploadExtraData === "function") { |
||
1340 | data = self.uploadExtraData(previewId, index); |
||
1341 | } |
||
1342 | return data; |
||
1343 | }, |
||
1344 | uploadExtra: function (previewId, index) { |
||
1345 | var self = this, data = self.getExtraData(previewId, index); |
||
1346 | if (data.length === 0) { |
||
1347 | return; |
||
1348 | } |
||
1349 | $.each(data, function (key, value) { |
||
1350 | self.formdata.append(key, value); |
||
1351 | }); |
||
1352 | }, |
||
1353 | setAsyncUploadStatus: function (previewId, pct, total) { |
||
1354 | var self = this, sum = 0; |
||
1355 | self.setProgress(pct, $('#' + previewId).find('.file-thumb-progress')); |
||
1356 | self.uploadStatus[previewId] = pct; |
||
1357 | $.each(self.uploadStatus, function (key, value) { |
||
1358 | sum += value; |
||
1359 | }); |
||
1360 | self.setProgress(Math.ceil(sum / total)); |
||
1361 | |||
1362 | }, |
||
1363 | initXhr: function (xhrobj, previewId, fileCount) { |
||
1364 | var self = this; |
||
1365 | if (xhrobj.upload) { |
||
1366 | xhrobj.upload.addEventListener('progress', function (event) { |
||
1367 | var pct = 0, position = event.loaded || event.position, total = event.total; |
||
1368 | /** @namespace event.lengthComputable */ |
||
1369 | if (event.lengthComputable) { |
||
1370 | pct = Math.ceil(position / total * 100); |
||
1371 | } |
||
1372 | if (previewId) { |
||
1373 | self.setAsyncUploadStatus(previewId, pct, fileCount); |
||
1374 | } else { |
||
1375 | self.setProgress(Math.ceil(pct)); |
||
1376 | } |
||
1377 | }, false); |
||
1378 | } |
||
1379 | return xhrobj; |
||
1380 | }, |
||
1381 | ajaxSubmit: function (fnBefore, fnSuccess, fnComplete, fnError, previewId, index) { |
||
1382 | var self = this, settings; |
||
1383 | self.raise('filepreajax', [previewId, index]); |
||
1384 | self.uploadExtra(previewId, index); |
||
1385 | settings = $.extend({ |
||
1386 | xhr: function () { |
||
1387 | var xhrobj = $.ajaxSettings.xhr(); |
||
1388 | return self.initXhr(xhrobj, previewId, self.getFileStack().length); |
||
1389 | }, |
||
1390 | url: self.uploadUrl, |
||
1391 | type: 'POST', |
||
1392 | dataType: 'json', |
||
1393 | data: self.formdata, |
||
1394 | cache: false, |
||
1395 | processData: false, |
||
1396 | contentType: false, |
||
1397 | beforeSend: fnBefore, |
||
1398 | success: fnSuccess, |
||
1399 | complete: fnComplete, |
||
1400 | error: fnError |
||
1401 | }, self.ajaxSettings); |
||
1402 | self.ajaxRequests.push($.ajax(settings)); |
||
1403 | }, |
||
1404 | initUploadSuccess: function (out, $thumb, allFiles) { |
||
1405 | var self = this, append, data, index, $newThumb, content, config, tags, i; |
||
1406 | if (!self.showPreview || typeof out !== 'object' || $.isEmptyObject(out)) { |
||
1407 | return; |
||
1408 | } |
||
1409 | if (out.initialPreview !== undefined && out.initialPreview.length > 0) { |
||
1410 | self.hasInitData = true; |
||
1411 | content = out.initialPreview || []; |
||
1412 | config = out.initialPreviewConfig || []; |
||
1413 | tags = out.initialPreviewThumbTags || []; |
||
1414 | append = out.append === undefined || out.append ? true : false; |
||
1415 | self.overwriteInitial = false; |
||
1416 | if ($thumb !== undefined) { |
||
1417 | if (!allFiles) { |
||
1418 | index = previewCache.add(self.id, content, config[0], tags[0], append); |
||
1419 | data = previewCache.get(self.id, index, false); |
||
1420 | $newThumb = $(data).hide(); |
||
1421 | $thumb.after($newThumb).fadeOut('slow', function () { |
||
1422 | $newThumb.fadeIn('slow').css('display:inline-block'); |
||
1423 | self.initPreviewDeletes(); |
||
1424 | self.clearFileInput(); |
||
1425 | $thumb.remove(); |
||
1426 | }); |
||
1427 | } else { |
||
1428 | i = $thumb.attr('data-fileindex'); |
||
1429 | self.uploadCache.content[i] = content[0]; |
||
1430 | self.uploadCache.config[i] = config[0]; |
||
1431 | self.uploadCache.tags[i] = tags[0]; |
||
1432 | self.uploadCache.append = append; |
||
1433 | } |
||
1434 | } else { |
||
1435 | previewCache.set(self.id, content, config, tags, append); |
||
1436 | self.initPreview(); |
||
1437 | self.initPreviewDeletes(); |
||
1438 | } |
||
1439 | } |
||
1440 | }, |
||
1441 | initSuccessThumbs: function () { |
||
1442 | var self = this; |
||
1443 | if (!self.showPreview) { |
||
1444 | return; |
||
1445 | } |
||
1446 | self.getThumbs('.file-preview-success').each(function () { |
||
1447 | var $thumb = $(this), $remove = $thumb.find('.kv-file-remove'); |
||
1448 | $remove.removeAttr('disabled'); |
||
1449 | handler($remove, 'click', function () { |
||
1450 | var out = self.raise('filesuccessremove', [$thumb.attr('id'), $thumb.data('fileindex')]); |
||
1451 | self.cleanMemory($thumb); |
||
1452 | if (out === false) { |
||
1453 | return; |
||
1454 | } |
||
1455 | $thumb.fadeOut('slow', function () { |
||
1456 | $thumb.remove(); |
||
1457 | if (!self.$preview.find('.file-preview-frame').length) { |
||
1458 | self.reset(); |
||
1459 | } |
||
1460 | }); |
||
1461 | }); |
||
1462 | }); |
||
1463 | }, |
||
1464 | checkAsyncComplete: function () { |
||
1465 | var self = this, previewId, i; |
||
1466 | for (i = 0; i < self.filestack.length; i++) { |
||
1467 | if (self.filestack[i]) { |
||
1468 | previewId = self.previewInitId + "-" + i; |
||
1469 | if ($.inArray(previewId, self.uploadLog) === -1) { |
||
1470 | return false; |
||
1471 | } |
||
1472 | } |
||
1473 | } |
||
1474 | return (self.uploadAsyncCount === self.uploadLog.length); |
||
1475 | }, |
||
1476 | uploadSingle: function (i, files, allFiles) { |
||
1477 | var self = this, total = self.getFileStack().length, formdata = new FormData(), outData, |
||
1478 | previewId = self.previewInitId + "-" + i, $thumb, chkComplete, $btnUpload, $btnDelete, |
||
1479 | hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData), |
||
1480 | fnBefore, fnSuccess, fnComplete, fnError, updateUploadLog, params = {id: previewId, index: i}; |
||
1481 | self.formdata = formdata; |
||
1482 | if (self.showPreview) { |
||
1483 | $thumb = $('#' + previewId + ':not(.file-preview-initial)'); |
||
1484 | $btnUpload = $thumb.find('.kv-file-upload'); |
||
1485 | $btnDelete = $thumb.find('.kv-file-remove'); |
||
1486 | $('#' + previewId).find('.file-thumb-progress').removeClass('hide'); |
||
1487 | } |
||
1488 | if (total === 0 || !hasPostData || ($btnUpload && $btnUpload.hasClass('disabled')) || self.abort(params)) { |
||
1489 | return; |
||
1490 | } |
||
1491 | updateUploadLog = function (i, previewId) { |
||
1492 | self.updateStack(i, undefined); |
||
1493 | self.uploadLog.push(previewId); |
||
1494 | if (self.checkAsyncComplete()) { |
||
1495 | self.fileBatchCompleted = true; |
||
1496 | } |
||
1497 | }; |
||
1498 | chkComplete = function () { |
||
1499 | if (!self.fileBatchCompleted) { |
||
1500 | return; |
||
1501 | } |
||
1502 | setTimeout(function () { |
||
1503 | if (self.showPreview) { |
||
1504 | previewCache.set( |
||
1505 | self.id, |
||
1506 | self.uploadCache.content, |
||
1507 | self.uploadCache.config, |
||
1508 | self.uploadCache.tags, |
||
1509 | self.uploadCache.append |
||
1510 | ); |
||
1511 | if (self.hasInitData) { |
||
1512 | self.initPreview(); |
||
1513 | self.initPreviewDeletes(); |
||
1514 | } |
||
1515 | } |
||
1516 | self.unlock(); |
||
1517 | self.clearFileInput(); |
||
1518 | self.raise('filebatchuploadcomplete', [self.filestack, self.getExtraData()]); |
||
1519 | self.uploadCount = 0; |
||
1520 | self.uploadStatus = {}; |
||
1521 | self.uploadLog = []; |
||
1522 | self.setProgress(100); |
||
1523 | }, 100); |
||
1524 | }; |
||
1525 | fnBefore = function (jqXHR) { |
||
1526 | outData = self.getOutData(jqXHR); |
||
1527 | self.fileBatchCompleted = false; |
||
1528 | if (self.showPreview) { |
||
1529 | if (!$thumb.hasClass('file-preview-success')) { |
||
1530 | self.setThumbStatus($thumb, 'Loading'); |
||
1531 | addCss($thumb, 'file-uploading'); |
||
1532 | } |
||
1533 | $btnUpload.attr('disabled', true); |
||
1534 | $btnDelete.attr('disabled', true); |
||
1535 | } |
||
1536 | if (!allFiles) { |
||
1537 | self.lock(); |
||
1538 | } |
||
1539 | self.raise('filepreupload', [outData, previewId, i]); |
||
1540 | params = $.extend(params, outData); |
||
1541 | if (self.abort(params)) { |
||
1542 | jqXHR.abort(); |
||
1543 | self.setProgress(100); |
||
1544 | } |
||
1545 | }; |
||
1546 | fnSuccess = function (data, textStatus, jqXHR) { |
||
1547 | outData = self.getOutData(jqXHR, data); |
||
1548 | params = $.extend(params, outData); |
||
1549 | setTimeout(function () { |
||
1550 | if (isEmpty(data) || isEmpty(data.error)) { |
||
1551 | if (self.showPreview) { |
||
1552 | self.setThumbStatus($thumb, 'Success'); |
||
1553 | $btnUpload.hide(); |
||
1554 | self.initUploadSuccess(data, $thumb, allFiles); |
||
1555 | } |
||
1556 | self.raise('fileuploaded', [outData, previewId, i]); |
||
1557 | if (!allFiles) { |
||
1558 | self.updateStack(i, undefined); |
||
1559 | } else { |
||
1560 | updateUploadLog(i, previewId); |
||
1561 | } |
||
1562 | } else { |
||
1563 | self.setThumbStatus($thumb, 'Error'); |
||
1564 | self.showUploadError(data.error, params); |
||
1565 | if (allFiles) { |
||
1566 | updateUploadLog(i, previewId); |
||
1567 | } |
||
1568 | } |
||
1569 | }, 100); |
||
1570 | }; |
||
1571 | fnComplete = function () { |
||
1572 | setTimeout(function () { |
||
1573 | if (self.showPreview) { |
||
1574 | $btnUpload.removeAttr('disabled'); |
||
1575 | $btnDelete.removeAttr('disabled'); |
||
1576 | $thumb.removeClass('file-uploading'); |
||
1577 | } |
||
1578 | if (!allFiles) { |
||
1579 | self.unlock(false); |
||
1580 | self.clearFileInput(); |
||
1581 | } else { |
||
1582 | chkComplete(); |
||
1583 | } |
||
1584 | self.initSuccessThumbs(); |
||
1585 | }, 100); |
||
1586 | }; |
||
1587 | fnError = function (jqXHR, textStatus, errorThrown) { |
||
1588 | var errMsg = self.parseError(jqXHR, errorThrown, (allFiles ? files[i].name : null)); |
||
1589 | setTimeout(function () { |
||
1590 | if (allFiles) { |
||
1591 | updateUploadLog(i, previewId); |
||
1592 | } |
||
1593 | self.uploadStatus[previewId] = 100; |
||
1594 | self.setThumbStatus($thumb, 'Error'); |
||
1595 | params = $.extend(params, self.getOutData(jqXHR)); |
||
1596 | self.showUploadError(errMsg, params); |
||
1597 | }, 100); |
||
1598 | }; |
||
1599 | formdata.append(self.uploadFileAttr, files[i], self.filenames[i]); |
||
1600 | formdata.append('file_id', i); |
||
1601 | self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, previewId, i); |
||
1602 | }, |
||
1603 | uploadBatch: function () { |
||
1604 | var self = this, files = self.filestack, total = files.length, params = {}, |
||
1605 | hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData), |
||
1606 | setAllUploaded, fnBefore, fnSuccess, fnComplete, fnError; |
||
1607 | self.formdata = new FormData(); |
||
1608 | if (total === 0 || !hasPostData || self.abort(params)) { |
||
1609 | return; |
||
1610 | } |
||
1611 | setAllUploaded = function () { |
||
1612 | $.each(files, function (key) { |
||
1613 | self.updateStack(key, undefined); |
||
1614 | }); |
||
1615 | self.clearFileInput(); |
||
1616 | }; |
||
1617 | fnBefore = function (jqXHR) { |
||
1618 | self.lock(); |
||
1619 | var outData = self.getOutData(jqXHR); |
||
1620 | if (self.showPreview) { |
||
1621 | self.getThumbs().each(function () { |
||
1622 | var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload'), |
||
1623 | $btnDelete = $thumb.find('.kv-file-remove'); |
||
1624 | if (!$thumb.hasClass('file-preview-success')) { |
||
1625 | self.setThumbStatus($thumb, 'Loading'); |
||
1626 | addCss($thumb, 'file-uploading'); |
||
1627 | } |
||
1628 | $btnUpload.attr('disabled', true); |
||
1629 | $btnDelete.attr('disabled', true); |
||
1630 | }); |
||
1631 | } |
||
1632 | self.raise('filebatchpreupload', [outData]); |
||
1633 | if (self.abort(outData)) { |
||
1634 | jqXHR.abort(); |
||
1635 | self.setProgress(100); |
||
1636 | } |
||
1637 | }; |
||
1638 | fnSuccess = function (data, textStatus, jqXHR) { |
||
1639 | /** @namespace data.errorkeys */ |
||
1640 | var outData = self.getOutData(jqXHR, data), $thumbs = self.getThumbs(), key = 0, |
||
1641 | keys = isEmpty(data) || isEmpty(data.errorkeys) ? [] : data.errorkeys; |
||
1642 | if (isEmpty(data) || isEmpty(data.error)) { |
||
1643 | self.raise('filebatchuploadsuccess', [outData]); |
||
1644 | setAllUploaded(); |
||
1645 | if (self.showPreview) { |
||
1646 | $thumbs.each(function () { |
||
1647 | var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload'); |
||
1648 | $thumb.find('.kv-file-upload').hide(); |
||
1649 | self.setThumbStatus($thumb, 'Success'); |
||
1650 | $thumb.removeClass('file-uploading'); |
||
1651 | $btnUpload.removeAttr('disabled'); |
||
1652 | }); |
||
1653 | self.initUploadSuccess(data); |
||
1654 | } else { |
||
1655 | self.reset(); |
||
1656 | } |
||
1657 | } else { |
||
1658 | if (self.showPreview) { |
||
1659 | $thumbs.each(function () { |
||
1660 | var $thumb = $(this), $btnDelete = $thumb.find('.kv-file-remove'), |
||
1661 | $btnUpload = $thumb.find('.kv-file-upload'); |
||
1662 | $thumb.removeClass('file-uploading'); |
||
1663 | $btnUpload.removeAttr('disabled'); |
||
1664 | $btnDelete.removeAttr('disabled'); |
||
1665 | if (keys.length === 0) { |
||
1666 | self.setThumbStatus($thumb, 'Error'); |
||
1667 | return; |
||
1668 | } |
||
1669 | if ($.inArray(key, keys) !== -1) { |
||
1670 | self.setThumbStatus($thumb, 'Error'); |
||
1671 | } else { |
||
1672 | $thumb.find('.kv-file-upload').hide(); |
||
1673 | self.setThumbStatus($thumb, 'Success'); |
||
1674 | self.updateStack(key, undefined); |
||
1675 | } |
||
1676 | key++; |
||
1677 | }); |
||
1678 | self.initUploadSuccess(data); |
||
1679 | } |
||
1680 | self.showUploadError(data.error, outData, 'filebatchuploaderror'); |
||
1681 | } |
||
1682 | }; |
||
1683 | fnComplete = function () { |
||
1684 | self.setProgress(100); |
||
1685 | self.unlock(); |
||
1686 | self.initSuccessThumbs(); |
||
1687 | self.clearFileInput(); |
||
1688 | self.raise('filebatchuploadcomplete', [self.filestack, self.getExtraData()]); |
||
1689 | }; |
||
1690 | fnError = function (jqXHR, textStatus, errorThrown) { |
||
1691 | var outData = self.getOutData(jqXHR), errMsg = self.parseError(jqXHR, errorThrown); |
||
1692 | self.showUploadError(errMsg, outData, 'filebatchuploaderror'); |
||
1693 | self.uploadFileCount = total - 1; |
||
1694 | if (!self.showPreview) { |
||
1695 | return; |
||
1696 | } |
||
1697 | self.getThumbs().each(function () { |
||
1698 | var $thumb = $(this), key = $thumb.attr('data-fileindex'); |
||
1699 | $thumb.removeClass('file-uploading'); |
||
1700 | if (self.filestack[key] !== undefined) { |
||
1701 | self.setThumbStatus($thumb, 'Error'); |
||
1702 | } |
||
1703 | }); |
||
1704 | self.getThumbs().removeClass('file-uploading'); |
||
1705 | self.getThumbs(' .kv-file-upload').removeAttr('disabled'); |
||
1706 | self.getThumbs(' .kv-file-delete').removeAttr('disabled'); |
||
1707 | }; |
||
1708 | $.each(files, function (key, data) { |
||
1709 | if (!isEmpty(files[key])) { |
||
1710 | self.formdata.append(self.uploadFileAttr, data, self.filenames[key]); |
||
1711 | } |
||
1712 | }); |
||
1713 | self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError); |
||
1714 | }, |
||
1715 | uploadExtraOnly: function () { |
||
1716 | var self = this, params = {}, fnBefore, fnSuccess, fnComplete, fnError; |
||
1717 | self.formdata = new FormData(); |
||
1718 | if (self.abort(params)) { |
||
1719 | return; |
||
1720 | } |
||
1721 | fnBefore = function (jqXHR) { |
||
1722 | self.lock(); |
||
1723 | var outData = self.getOutData(jqXHR); |
||
1724 | self.raise('filebatchpreupload', [outData]); |
||
1725 | self.setProgress(50); |
||
1726 | params.data = outData; |
||
1727 | params.xhr = jqXHR; |
||
1728 | if (self.abort(params)) { |
||
1729 | jqXHR.abort(); |
||
1730 | self.setProgress(100); |
||
1731 | } |
||
1732 | }; |
||
1733 | fnSuccess = function (data, textStatus, jqXHR) { |
||
1734 | var outData = self.getOutData(jqXHR, data); |
||
1735 | if (isEmpty(data) || isEmpty(data.error)) { |
||
1736 | self.raise('filebatchuploadsuccess', [outData]); |
||
1737 | self.clearFileInput(); |
||
1738 | self.initUploadSuccess(data); |
||
1739 | } else { |
||
1740 | self.showUploadError(data.error, outData, 'filebatchuploaderror'); |
||
1741 | } |
||
1742 | }; |
||
1743 | fnComplete = function () { |
||
1744 | self.setProgress(100); |
||
1745 | self.unlock(); |
||
1746 | self.clearFileInput(); |
||
1747 | self.raise('filebatchuploadcomplete', [self.filestack, self.getExtraData()]); |
||
1748 | }; |
||
1749 | fnError = function (jqXHR, textStatus, errorThrown) { |
||
1750 | var outData = self.getOutData(jqXHR), errMsg = self.parseError(jqXHR, errorThrown); |
||
1751 | params.data = outData; |
||
1752 | self.showUploadError(errMsg, outData, 'filebatchuploaderror'); |
||
1753 | }; |
||
1754 | self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError); |
||
1755 | }, |
||
1756 | upload: function () { |
||
1757 | var self = this, totLen = self.getFileStack().length, params = {}, |
||
1758 | i, outData, len, hasExtraData = !$.isEmptyObject(self.getExtraData()); |
||
1759 | if (self.minFileCount > 0 && self.getFileCount(totLen) < self.minFileCount) { |
||
1760 | self.noFilesError(params); |
||
1761 | return; |
||
1762 | } |
||
1763 | if (!self.isUploadable || self.isDisabled || (totLen === 0 && !hasExtraData)) { |
||
1764 | return; |
||
1765 | } |
||
1766 | self.resetUpload(); |
||
1767 | self.$progress.removeClass('hide'); |
||
1768 | self.uploadCount = 0; |
||
1769 | self.uploadStatus = {}; |
||
1770 | self.uploadLog = []; |
||
1771 | self.lock(); |
||
1772 | self.setProgress(2); |
||
1773 | if (totLen === 0 && hasExtraData) { |
||
1774 | self.uploadExtraOnly(); |
||
1775 | return; |
||
1776 | } |
||
1777 | len = self.filestack.length; |
||
1778 | self.hasInitData = false; |
||
1779 | if (self.uploadAsync) { |
||
1780 | outData = self.getOutData(); |
||
1781 | self.raise('filebatchpreupload', [outData]); |
||
1782 | self.fileBatchCompleted = false; |
||
1783 | self.uploadCache = {content: [], config: [], tags: [], append: true}; |
||
1784 | self.uploadAsyncCount = self.getFileStack().length; |
||
1785 | for (i = 0; i < len; i++) { |
||
1786 | self.uploadCache.content[i] = null; |
||
1787 | self.uploadCache.config[i] = null; |
||
1788 | self.uploadCache.tags[i] = null; |
||
1789 | } |
||
1790 | for (i = 0; i < len; i++) { |
||
1791 | if (self.filestack[i] !== undefined) { |
||
1792 | self.uploadSingle(i, self.filestack, true); |
||
1793 | } |
||
1794 | } |
||
1795 | return; |
||
1796 | } |
||
1797 | self.uploadBatch(); |
||
1798 | }, |
||
1799 | initFileActions: function () { |
||
1800 | var self = this; |
||
1801 | if (!self.showPreview) { |
||
1802 | return; |
||
1803 | } |
||
1804 | self.$preview.find('.kv-file-remove').each(function () { |
||
1805 | var $el = $(this), $frame = $el.closest('.file-preview-frame'), hasError, |
||
1806 | id = $frame.attr('id'), ind = $frame.attr('data-fileindex'), n, cap, status; |
||
1807 | handler($el, 'click', function () { |
||
1808 | status = self.raise('filepreremove', [id, ind]); |
||
1809 | if (status === false || !self.validateMinCount()) { |
||
1810 | return false; |
||
1811 | } |
||
1812 | hasError = $frame.hasClass('file-preview-error'); |
||
1813 | self.cleanMemory($frame); |
||
1814 | $frame.fadeOut('slow', function () { |
||
1815 | self.updateStack(ind, undefined); |
||
1816 | self.clearObjects($frame); |
||
1817 | $frame.remove(); |
||
1818 | if (id && hasError) { |
||
1819 | self.$errorContainer.find('li[data-file-id="' + id + '"]').fadeOut('fast', function () { |
||
1820 | $(this).remove(); |
||
1821 | if (!self.errorsExist()) { |
||
1822 | self.resetErrors(); |
||
1823 | } |
||
1824 | }); |
||
1825 | } |
||
1826 | var filestack = self.getFileStack(true), len = filestack.length, chk = previewCache.count( |
||
1827 | self.id), |
||
1828 | hasThumb = self.showPreview && self.$preview.find('.file-preview-frame').length; |
||
1829 | self.clearFileInput(); |
||
1830 | if (len === 0 && chk === 0 && !hasThumb) { |
||
1831 | self.reset(); |
||
1832 | } else { |
||
1833 | n = chk + len; |
||
1834 | cap = n > 1 ? self.getMsgSelected(n) : (filestack[0] ? self.getFileNames()[0] : ''); |
||
1835 | self.setCaption(cap); |
||
1836 | } |
||
1837 | self.raise('fileremoved', [id, ind]); |
||
1838 | }); |
||
1839 | }); |
||
1840 | }); |
||
1841 | self.$preview.find('.kv-file-upload').each(function () { |
||
1842 | var $el = $(this); |
||
1843 | handler($el, 'click', function () { |
||
1844 | var $frame = $el.closest('.file-preview-frame'), |
||
1845 | ind = $frame.attr('data-fileindex'); |
||
1846 | if (!$frame.hasClass('file-preview-error')) { |
||
1847 | self.uploadSingle(ind, self.filestack, false); |
||
1848 | } |
||
1849 | }); |
||
1850 | }); |
||
1851 | }, |
||
1852 | hideFileIcon: function () { |
||
1853 | if (this.overwriteInitial) { |
||
1854 | this.$captionContainer.find('.kv-caption-icon').hide(); |
||
1855 | } |
||
1856 | }, |
||
1857 | showFileIcon: function () { |
||
1858 | this.$captionContainer.find('.kv-caption-icon').show(); |
||
1859 | }, |
||
1860 | addError: function (msg) { |
||
1861 | var self = this, $error = self.$errorContainer; |
||
1862 | if (msg && $error.length) { |
||
1863 | $error.html(self.errorCloseButton + msg); |
||
1864 | $error.find('.kv-error-close').off('click').on('click', function () { |
||
1865 | $error.fadeOut('slow'); |
||
1866 | }); |
||
1867 | } |
||
1868 | }, |
||
1869 | resetErrors: function (fade) { |
||
1870 | var self = this, $error = self.$errorContainer; |
||
1871 | self.isError = false; |
||
1872 | self.$container.removeClass('has-error'); |
||
1873 | $error.html(''); |
||
1874 | if (fade) { |
||
1875 | $error.fadeOut('slow'); |
||
1876 | } else { |
||
1877 | $error.hide(); |
||
1878 | } |
||
1879 | }, |
||
1880 | showFolderError: function (folders) { |
||
1881 | var self = this, $error = self.$errorContainer; |
||
1882 | if (!folders) { |
||
1883 | return; |
||
1884 | } |
||
1885 | self.addError(self.msgFoldersNotAllowed.replace(/\{n}/g, folders)); |
||
1886 | $error.fadeIn(800); |
||
1887 | addCss(self.$container, 'has-error'); |
||
1888 | self.raise('filefoldererror', [folders]); |
||
1889 | }, |
||
1890 | showUploadError: function (msg, params, event) { |
||
1891 | var self = this, $error = self.$errorContainer, ev = event || 'fileuploaderror', |
||
1892 | e = params && params.id ? '<li data-file-id="' + params.id + '">' + msg + '</li>' : '<li>' + msg + '</li>'; |
||
1893 | if ($error.find('ul').length === 0) { |
||
1894 | self.addError('<ul>' + e + '</ul>'); |
||
1895 | } else { |
||
1896 | $error.find('ul').append(e); |
||
1897 | } |
||
1898 | $error.fadeIn(800); |
||
1899 | self.raise(ev, [params]); |
||
1900 | self.$container.removeClass('file-input-new'); |
||
1901 | addCss(self.$container, 'has-error'); |
||
1902 | return true; |
||
1903 | }, |
||
1904 | showError: function (msg, params, event) { |
||
1905 | var self = this, $error = self.$errorContainer, ev = event || 'fileerror'; |
||
1906 | params = params || {}; |
||
1907 | params.reader = self.reader; |
||
1908 | self.addError(msg); |
||
1909 | $error.fadeIn(800); |
||
1910 | self.raise(ev, [params]); |
||
1911 | if (!self.isUploadable) { |
||
1912 | self.clearFileInput(); |
||
1913 | } |
||
1914 | self.$container.removeClass('file-input-new'); |
||
1915 | addCss(self.$container, 'has-error'); |
||
1916 | self.$btnUpload.attr('disabled', true); |
||
1917 | return true; |
||
1918 | }, |
||
1919 | errorHandler: function (evt, caption) { |
||
1920 | var self = this, err = evt.target.error; |
||
1921 | /** @namespace err.NOT_FOUND_ERR */ |
||
1922 | /** @namespace err.SECURITY_ERR */ |
||
1923 | /** @namespace err.NOT_READABLE_ERR */ |
||
1924 | if (err.code === err.NOT_FOUND_ERR) { |
||
1925 | self.showError(self.msgFileNotFound.replace('{name}', caption)); |
||
1926 | } else if (err.code === err.SECURITY_ERR) { |
||
1927 | self.showError(self.msgFileSecured.replace('{name}', caption)); |
||
1928 | } else if (err.code === err.NOT_READABLE_ERR) { |
||
1929 | self.showError(self.msgFileNotReadable.replace('{name}', caption)); |
||
1930 | } else if (err.code === err.ABORT_ERR) { |
||
1931 | self.showError(self.msgFilePreviewAborted.replace('{name}', caption)); |
||
1932 | } else { |
||
1933 | self.showError(self.msgFilePreviewError.replace('{name}', caption)); |
||
1934 | } |
||
1935 | }, |
||
1936 | parseFileType: function (file) { |
||
1937 | var self = this, isValid, vType, cat, i; |
||
1938 | for (i = 0; i < defaultPreviewTypes.length; i += 1) { |
||
1939 | cat = defaultPreviewTypes[i]; |
||
1940 | isValid = isSet(cat, self.fileTypeSettings) ? self.fileTypeSettings[cat] : defaultFileTypeSettings[cat]; |
||
1941 | vType = isValid(file.type, file.name) ? cat : ''; |
||
1942 | if (!isEmpty(vType)) { |
||
1943 | return vType; |
||
1944 | } |
||
1945 | } |
||
1946 | return 'other'; |
||
1947 | }, |
||
1948 | previewDefault: function (file, previewId, isDisabled) { |
||
1949 | if (!this.showPreview) { |
||
1950 | return; |
||
1951 | } |
||
1952 | var self = this, frameClass = '', fname = file ? file.name : '', |
||
1953 | /** @namespace objUrl.createObjectURL */ |
||
1954 | data = objUrl.createObjectURL(file), ind = previewId.slice(previewId.lastIndexOf('-') + 1), |
||
1955 | config = self.previewSettings.other || defaultPreviewSettings.other, |
||
1956 | footer = self.renderFileFooter(file.name, config.width), |
||
1957 | previewOtherTemplate = self.parseFilePreviewIcon(self.getPreviewTemplate('other'), fname); |
||
1958 | if (isDisabled === true) { |
||
1959 | if (!self.isUploadable) { |
||
1960 | footer += '<div class="file-other-error" title="' + self.fileActionSettings.indicatorErrorTitle + |
||
1961 | '">' + self.fileActionSettings.indicatorError + '</div>'; |
||
1962 | } |
||
1963 | } |
||
1964 | self.clearDefaultPreview(); |
||
1965 | self.$preview.append("\n" + previewOtherTemplate |
||
1966 | .replace(/\{previewId}/g, previewId) |
||
1967 | .replace(/\{frameClass}/g, frameClass) |
||
1968 | .replace(/\{fileindex}/g, ind) |
||
1969 | .replace(/\{caption}/g, self.slug(file.name)) |
||
1970 | .replace(/\{width}/g, config.width) |
||
1971 | .replace(/\{height}/g, config.height) |
||
1972 | .replace(/\{type}/g, file.type) |
||
1973 | .replace(/\{data}/g, data) |
||
1974 | .replace(/\{footer}/g, footer)); |
||
1975 | if (isDisabled === true && self.isUploadable) { |
||
1976 | self.setThumbStatus($('#' + previewId), 'Error'); |
||
1977 | } |
||
1978 | }, |
||
1979 | previewFile: function (i, file, theFile, previewId, data) { |
||
1980 | if (!this.showPreview) { |
||
1981 | return; |
||
1982 | } |
||
1983 | var self = this, cat = self.parseFileType(file), fname = file ? file.name : '', caption = self.slug(fname), |
||
1984 | content, strText, types = self.allowedPreviewTypes, mimes = self.allowedPreviewMimeTypes, |
||
1985 | tmplt = self.getPreviewTemplate(cat), chkTypes = types && types.indexOf(cat) >= 0, id, |
||
1986 | config = isSet(cat, self.previewSettings) ? self.previewSettings[cat] : defaultPreviewSettings[cat], |
||
1987 | chkMimes = mimes && mimes.indexOf(file.type) !== -1, |
||
1988 | footer = self.renderFileFooter(caption, config.width), modal = '', |
||
1989 | ind = previewId.slice(previewId.lastIndexOf('-') + 1); |
||
1990 | if (chkTypes || chkMimes) { |
||
1991 | tmplt = self.parseFilePreviewIcon(tmplt, fname.split('.').pop()); |
||
1992 | if (cat === 'text') { |
||
1993 | strText = htmlEncode(theFile.target.result); |
||
1994 | id = 'text-' + uniqId(); |
||
1995 | content = tmplt.replace(/\{zoom}/g, self.getLayoutTemplate('zoom')); |
||
1996 | modal = self.getLayoutTemplate('modal').replace('{id}', id) |
||
1997 | .replace(/\{title}/g, caption) |
||
1998 | .replace(/\{body}/g, strText).replace(/\{heading}/g, self.msgZoomModalHeading); |
||
1999 | content = content.replace(/\{previewId}/g, previewId).replace(/\{caption}/g, caption) |
||
2000 | .replace(/\{width}/g, config.width).replace(/\{height}/g, config.height) |
||
2001 | .replace(/\{frameClass}/g, '').replace(/\{zoomInd}/g, self.zoomIndicator) |
||
2002 | .replace(/\{footer}/g, footer).replace(/\{fileindex}/g, ind) |
||
2003 | .replace(/\{type}/g, file.type).replace(/\{zoomTitle}/g, self.msgZoomTitle) |
||
2004 | .replace(/\{dialog}/g, "$('#" + id + "').modal('show')") |
||
2005 | .replace(/\{data}/g, strText) + modal; |
||
2006 | } else { |
||
2007 | content = tmplt.replace(/\{previewId}/g, previewId).replace(/\{caption}/g, caption) |
||
2008 | .replace(/\{frameClass}/g, '').replace(/\{type}/g, file.type).replace(/\{fileindex}/g, ind) |
||
2009 | .replace(/\{width}/g, config.width).replace(/\{height}/g, config.height) |
||
2010 | .replace(/\{footer}/g, footer).replace(/\{data}/g, data); |
||
2011 | } |
||
2012 | self.clearDefaultPreview(); |
||
2013 | self.$preview.append("\n" + content); |
||
2014 | self.validateImage(i, previewId, caption, file.type); |
||
2015 | } else { |
||
2016 | self.previewDefault(file, previewId); |
||
2017 | } |
||
2018 | }, |
||
2019 | slugDefault: function (text) { |
||
2020 | return isEmpty(text) ? '' : text.split(/(\\|\/)/g).pop().replace(/[^\w\u00C0-\u017F\-.\\\/ ]+/g, ''); |
||
2021 | }, |
||
2022 | readFiles: function (files) { |
||
2023 | this.reader = new FileReader(); |
||
2024 | var self = this, $el = self.$element, $preview = self.$preview, reader = self.reader, |
||
2025 | $container = self.$previewContainer, $status = self.$previewStatus, msgLoading = self.msgLoading, |
||
2026 | msgProgress = self.msgProgress, previewInitId = self.previewInitId, numFiles = files.length, |
||
2027 | settings = self.fileTypeSettings, ctr = self.filestack.length, readFile, |
||
2028 | throwError = function (msg, file, previewId, index) { |
||
2029 | var p1 = $.extend(self.getOutData({}, {}, files), {id: previewId, index: index}), |
||
2030 | p2 = {id: previewId, index: index, file: file, files: files}; |
||
2031 | self.previewDefault(file, previewId, true); |
||
2032 | if (self.isUploadable) { |
||
2033 | self.pushStack(undefined); |
||
2034 | } |
||
2035 | setTimeout(readFile(index + 1), 100); |
||
2036 | self.initFileActions(); |
||
2037 | return self.isUploadable ? self.showUploadError(msg, p1) : self.showError(msg, p2); |
||
2038 | }; |
||
2039 | |||
2040 | self.loadedImages = []; |
||
2041 | self.totalImagesCount = 0; |
||
2042 | |||
2043 | $.each(files, function (key, file) { |
||
2044 | var cat = 'image', |
||
2045 | func = isSet(cat, |
||
2046 | self.fileTypeSettings) ? self.fileTypeSettings[cat] : defaultFileTypeSettings[cat]; |
||
2047 | if (func && func(file.type)) { |
||
2048 | self.totalImagesCount++; |
||
2049 | } |
||
2050 | }); |
||
2051 | |||
2052 | readFile = function (i) { |
||
2053 | if (isEmpty($el.attr('multiple'))) { |
||
2054 | numFiles = 1; |
||
2055 | } |
||
2056 | if (i >= numFiles) { |
||
2057 | if (self.isUploadable && self.filestack.length > 0) { |
||
2058 | self.raise('filebatchselected', [self.getFileStack()]); |
||
2059 | } else { |
||
2060 | self.raise('filebatchselected', [files]); |
||
2061 | } |
||
2062 | $container.removeClass('file-thumb-loading'); |
||
2063 | $status.html(''); |
||
2064 | return; |
||
2065 | } |
||
2066 | var node = ctr + i, previewId = previewInitId + "-" + node, isText, file = files[i], |
||
2067 | caption = self.slug(file.name), fileSize = (file.size || 0) / 1000, checkFile, fileExtExpr = '', |
||
2068 | previewData = objUrl.createObjectURL(file), fileCount = 0, j, msg, typ, chk, |
||
2069 | fileTypes = self.allowedFileTypes, strTypes = isEmpty(fileTypes) ? '' : fileTypes.join(', '), |
||
2070 | fileExt = self.allowedFileExtensions, strExt = isEmpty(fileExt) ? '' : fileExt.join(', '); |
||
2071 | if (!isEmpty(fileExt)) { |
||
2072 | fileExtExpr = new RegExp('\\.(' + fileExt.join('|') + ')$', 'i'); |
||
2073 | } |
||
2074 | fileSize = fileSize.toFixed(2); |
||
2075 | if (self.maxFileSize > 0 && fileSize > self.maxFileSize) { |
||
2076 | msg = self.msgSizeTooLarge.replace('{name}', caption) |
||
2077 | .replace('{size}', fileSize) |
||
2078 | .replace('{maxSize}', self.maxFileSize); |
||
2079 | self.isError = throwError(msg, file, previewId, i); |
||
2080 | return; |
||
2081 | } |
||
2082 | if (!isEmpty(fileTypes) && isArray(fileTypes)) { |
||
2083 | for (j = 0; j < fileTypes.length; j += 1) { |
||
2084 | typ = fileTypes[j]; |
||
2085 | checkFile = settings[typ]; |
||
2086 | chk = (checkFile !== undefined && checkFile(file.type, caption)); |
||
2087 | fileCount += isEmpty(chk) ? 0 : chk.length; |
||
2088 | } |
||
2089 | if (fileCount === 0) { |
||
2090 | msg = self.msgInvalidFileType.replace('{name}', caption).replace('{types}', strTypes); |
||
2091 | self.isError = throwError(msg, file, previewId, i); |
||
2092 | return; |
||
2093 | } |
||
2094 | } |
||
2095 | if (fileCount === 0 && !isEmpty(fileExt) && isArray(fileExt) && !isEmpty(fileExtExpr)) { |
||
2096 | chk = caption.match(fileExtExpr); |
||
2097 | fileCount += isEmpty(chk) ? 0 : chk.length; |
||
2098 | if (fileCount === 0) { |
||
2099 | msg = self.msgInvalidFileExtension.replace('{name}', caption).replace('{extensions}', |
||
2100 | strExt); |
||
2101 | self.isError = throwError(msg, file, previewId, i); |
||
2102 | return; |
||
2103 | } |
||
2104 | } |
||
2105 | if (!self.showPreview) { |
||
2106 | self.pushStack(file); |
||
2107 | setTimeout(readFile(i + 1), 100); |
||
2108 | self.raise('fileloaded', [file, previewId, i, reader]); |
||
2109 | return; |
||
2110 | } |
||
2111 | if ($preview.length > 0 && FileReader !== undefined) { |
||
0 ignored issues
–
show
Comprehensibility
Bug
Compatibility
introduced
by
![]() |
|||
2112 | $status.html(msgLoading.replace('{index}', i + 1).replace('{files}', numFiles)); |
||
2113 | $container.addClass('file-thumb-loading'); |
||
2114 | reader.onerror = function (evt) { |
||
2115 | self.errorHandler(evt, caption); |
||
2116 | }; |
||
2117 | reader.onload = function (theFile) { |
||
2118 | self.previewFile(i, file, theFile, previewId, previewData); |
||
2119 | self.initFileActions(); |
||
2120 | }; |
||
2121 | reader.onloadend = function () { |
||
2122 | msg = msgProgress |
||
2123 | .replace('{index}', i + 1).replace('{files}', numFiles) |
||
2124 | .replace('{percent}', 50).replace('{name}', caption); |
||
2125 | setTimeout(function () { |
||
2126 | $status.html(msg); |
||
2127 | self.updateFileDetails(numFiles); |
||
2128 | readFile(i + 1); |
||
2129 | }, 100); |
||
2130 | self.raise('fileloaded', [file, previewId, i, reader]); |
||
2131 | }; |
||
2132 | reader.onprogress = function (data) { |
||
2133 | if (data.lengthComputable) { |
||
2134 | var fact = (data.loaded / data.total) * 100, progress = Math.ceil(fact); |
||
2135 | msg = msgProgress.replace('{index}', i + 1).replace('{files}', numFiles) |
||
2136 | .replace('{percent}', progress).replace('{name}', caption); |
||
2137 | setTimeout(function () { |
||
2138 | $status.html(msg); |
||
2139 | }, 100); |
||
2140 | } |
||
2141 | }; |
||
2142 | isText = isSet('text', settings) ? settings.text : defaultFileTypeSettings.text; |
||
2143 | if (isText(file.type, caption)) { |
||
2144 | reader.readAsText(file, self.textEncoding); |
||
2145 | } else { |
||
2146 | reader.readAsArrayBuffer(file); |
||
2147 | } |
||
2148 | } else { |
||
2149 | self.previewDefault(file, previewId); |
||
2150 | setTimeout(function () { |
||
2151 | readFile(i + 1); |
||
2152 | self.updateFileDetails(numFiles); |
||
2153 | }, 100); |
||
2154 | self.raise('fileloaded', [file, previewId, i, reader]); |
||
2155 | } |
||
2156 | self.pushStack(file); |
||
2157 | }; |
||
2158 | |||
2159 | readFile(0); |
||
2160 | self.updateFileDetails(numFiles, false); |
||
2161 | }, |
||
2162 | updateFileDetails: function (numFiles) { |
||
2163 | var self = this, $el = self.$element, fileStack = self.getFileStack(), |
||
2164 | name = $el.val() || (fileStack.length && fileStack[0].name) || '', label = self.slug(name), |
||
2165 | n = self.isUploadable ? fileStack.length : numFiles, |
||
2166 | nFiles = previewCache.count(self.id) + n, |
||
2167 | log = n > 1 ? self.getMsgSelected(nFiles) : label; |
||
2168 | if (self.isError) { |
||
2169 | self.$previewContainer.removeClass('file-thumb-loading'); |
||
2170 | self.$previewStatus.html(''); |
||
2171 | self.$captionContainer.find('.kv-caption-icon').hide(); |
||
2172 | } else { |
||
2173 | self.showFileIcon(); |
||
2174 | } |
||
2175 | self.setCaption(log, self.isError); |
||
2176 | self.$container.removeClass('file-input-new file-input-ajax-new'); |
||
2177 | if (arguments.length === 1) { |
||
2178 | self.raise('fileselect', [numFiles, label]); |
||
2179 | } |
||
2180 | if (previewCache.count(self.id)) { |
||
2181 | self.initPreviewDeletes(); |
||
2182 | } |
||
2183 | }, |
||
2184 | validateMinCount: function () { |
||
2185 | var self = this, len = self.isUploadable ? self.getFileStack().length : self.$element.get(0).files.length; |
||
2186 | if (self.validateInitialCount && self.minFileCount > 0 && self.getFileCount(len - 1) < self.minFileCount) { |
||
2187 | self.noFilesError({}); |
||
2188 | return false; |
||
2189 | } |
||
2190 | return true; |
||
2191 | }, |
||
2192 | getFileCount: function (fileCount) { |
||
2193 | var self = this, addCount = 0; |
||
2194 | if (self.validateInitialCount && !self.overwriteInitial) { |
||
2195 | addCount = previewCache.count(self.id); |
||
2196 | fileCount += addCount; |
||
2197 | } |
||
2198 | return fileCount; |
||
2199 | }, |
||
2200 | change: function (e) { |
||
2201 | var self = this, $el = self.$element; |
||
2202 | if (!self.isUploadable && isEmpty($el.val()) && self.fileInputCleared) { // IE 11 fix |
||
2203 | self.fileInputCleared = false; |
||
2204 | return; |
||
2205 | } |
||
2206 | self.fileInputCleared = false; |
||
2207 | var tfiles, msg, total, isDragDrop = arguments.length > 1, |
||
2208 | files = isDragDrop ? e.originalEvent.dataTransfer.files : $el.get(0).files, |
||
2209 | isSingleUpload = isEmpty($el.attr('multiple')), i = 0, f, n, folders = 0, |
||
2210 | ctr = self.filestack.length, isAjaxUpload = self.isUploadable, len, |
||
2211 | flagSingle = (isSingleUpload && ctr > 0), |
||
2212 | throwError = function (mesg, file, previewId, index) { |
||
2213 | var p1 = $.extend(self.getOutData({}, {}, files), {id: previewId, index: index}), |
||
2214 | p2 = {id: previewId, index: index, file: file, files: files}; |
||
2215 | return self.isUploadable ? self.showUploadError(mesg, p1) : self.showError(mesg, p2); |
||
2216 | }; |
||
2217 | self.reader = null; |
||
2218 | self.resetUpload(); |
||
2219 | self.hideFileIcon(); |
||
2220 | if (self.isUploadable) { |
||
2221 | self.$container.find('.file-drop-zone .' + self.dropZoneTitleClass).remove(); |
||
2222 | } |
||
2223 | if (isDragDrop) { |
||
2224 | tfiles = []; |
||
2225 | while (files[i]) { |
||
2226 | f = files[i]; |
||
2227 | if (!f.type && f.size % 4096 === 0) { |
||
2228 | folders++; |
||
2229 | } else { |
||
2230 | tfiles.push(f); |
||
2231 | } |
||
2232 | i++; |
||
2233 | } |
||
2234 | } else { |
||
2235 | if (e.target.files === undefined) { |
||
2236 | tfiles = e.target && e.target.value ? [ |
||
2237 | {name: e.target.value.replace(/^.+\\/, '')} |
||
2238 | ] : []; |
||
2239 | } else { |
||
2240 | tfiles = e.target.files; |
||
2241 | } |
||
2242 | } |
||
2243 | if (isEmpty(tfiles) || tfiles.length === 0) { |
||
2244 | if (!isAjaxUpload) { |
||
2245 | self.clear(); |
||
2246 | } |
||
2247 | self.showFolderError(folders); |
||
2248 | self.raise('fileselectnone'); |
||
2249 | return; |
||
2250 | } |
||
2251 | self.resetErrors(); |
||
2252 | len = tfiles.length; |
||
2253 | total = self.isUploadable ? self.getFileStack().length + len : len; |
||
2254 | total = self.getFileCount(total); |
||
2255 | if (self.maxFileCount > 0 && total > self.maxFileCount) { |
||
2256 | if (!self.autoReplace || len > self.maxFileCount) { |
||
2257 | n = (self.autoReplace && len > self.maxFileCount) ? len : total; |
||
2258 | msg = self.msgFilesTooMany.replace('{m}', self.maxFileCount).replace('{n}', n); |
||
2259 | self.isError = throwError(msg, null, null, null); |
||
2260 | self.$captionContainer.find('.kv-caption-icon').hide(); |
||
2261 | self.setCaption('', true); |
||
2262 | self.$container.removeClass('file-input-new file-input-ajax-new'); |
||
2263 | return; |
||
2264 | } |
||
2265 | if (total > self.maxFileCount) { |
||
2266 | self.resetPreviewThumbs(isAjaxUpload); |
||
2267 | } |
||
2268 | } else { |
||
2269 | if (!isAjaxUpload || flagSingle) { |
||
2270 | self.resetPreviewThumbs(false); |
||
2271 | if (flagSingle) { |
||
2272 | self.clearStack(); |
||
2273 | } |
||
2274 | } else { |
||
2275 | if (isAjaxUpload && ctr === 0 && (!previewCache.count(self.id) || self.overwriteInitial)) { |
||
2276 | self.resetPreviewThumbs(true); |
||
2277 | } |
||
2278 | } |
||
2279 | } |
||
2280 | if (self.isPreviewable) { |
||
2281 | self.readFiles(tfiles); |
||
2282 | } else { |
||
2283 | self.updateFileDetails(1); |
||
2284 | } |
||
2285 | self.showFolderError(folders); |
||
2286 | }, |
||
2287 | getFileName: function (file) { |
||
2288 | return file && file.name ? this.slug(file.name) : undefined; |
||
2289 | }, |
||
2290 | getFileNames: function (skipNull) { |
||
2291 | var self = this; |
||
2292 | return self.filenames.filter(function (n) { |
||
2293 | return (skipNull ? n !== undefined : n !== undefined && n !== null); |
||
2294 | }); |
||
2295 | }, |
||
2296 | getFileStack: function (skipNull) { |
||
2297 | var self = this; |
||
2298 | return self.filestack.filter(function (n) { |
||
2299 | return (skipNull ? n !== undefined : n !== undefined && n !== null); |
||
2300 | }); |
||
2301 | }, |
||
2302 | clearStack: function () { |
||
2303 | var self = this; |
||
2304 | self.filestack = []; |
||
2305 | self.filenames = []; |
||
2306 | }, |
||
2307 | updateStack: function (i, file) { |
||
2308 | var self = this; |
||
2309 | self.filestack[i] = file; |
||
2310 | self.filenames[i] = self.getFileName(file); |
||
2311 | }, |
||
2312 | pushStack: function (file) { |
||
2313 | var self = this; |
||
2314 | self.filestack.push(file); |
||
2315 | self.filenames.push(self.getFileName(file)); |
||
2316 | }, |
||
2317 | checkDimensions: function (i, chk, $img, $thumb, fname, type, params) { |
||
2318 | var self = this, msg, dim, tag = chk === 'Small' ? 'min' : 'max', |
||
2319 | limit = self[tag + 'Image' + type], $imgEl, isValid; |
||
2320 | if (isEmpty(limit) || !$img.length) { |
||
2321 | return; |
||
2322 | } |
||
2323 | $imgEl = $img[0]; |
||
2324 | dim = (type === 'Width') ? $imgEl.naturalWidth || $imgEl.width : $imgEl.naturalHeight || $imgEl.height; |
||
2325 | isValid = chk === 'Small' ? dim >= limit : dim <= limit; |
||
2326 | if (isValid) { |
||
2327 | return; |
||
2328 | } |
||
2329 | msg = self['msgImage' + type + chk].replace('{name}', fname).replace('{size}', limit); |
||
2330 | self.showUploadError(msg, params); |
||
2331 | self.setThumbStatus($thumb, 'Error'); |
||
2332 | self.updateStack(i, null); |
||
2333 | }, |
||
2334 | validateImage: function (i, previewId, fname, ftype) { |
||
2335 | var self = this, $preview = self.$preview, params, w1, w2, |
||
2336 | $thumb = $preview.find("#" + previewId), $img = $thumb.find('img'); |
||
2337 | fname = fname || 'Untitled'; |
||
2338 | if (!$img.length) { |
||
2339 | return; |
||
2340 | } |
||
2341 | handler($img, 'load', function () { |
||
2342 | w1 = $thumb.width(); |
||
2343 | w2 = $preview.width(); |
||
2344 | if (w1 > w2) { |
||
2345 | $img.css('width', '100%'); |
||
2346 | $thumb.css('width', '97%'); |
||
2347 | } |
||
2348 | params = {ind: i, id: previewId}; |
||
2349 | self.checkDimensions(i, 'Small', $img, $thumb, fname, 'Width', params); |
||
2350 | self.checkDimensions(i, 'Small', $img, $thumb, fname, 'Height', params); |
||
2351 | if (!self.resizeImage) { |
||
2352 | self.checkDimensions(i, 'Large', $img, $thumb, fname, 'Width', params); |
||
2353 | self.checkDimensions(i, 'Large', $img, $thumb, fname, 'Height', params); |
||
2354 | } |
||
2355 | self.raise('fileimageloaded', [previewId]); |
||
2356 | self.loadedImages.push({ind: i, img: $img, thumb: $thumb, pid: previewId, typ: ftype}); |
||
2357 | self.validateAllImages(); |
||
2358 | objUrl.revokeObjectURL($img.attr('src')); |
||
2359 | }); |
||
2360 | }, |
||
2361 | validateAllImages: function () { |
||
2362 | var self = this, i, config, $img, $thumb, pid, ind, params = {}, errFunc; |
||
2363 | if (self.loadedImages.length !== self.totalImagesCount) { |
||
2364 | return; |
||
2365 | } |
||
2366 | self.raise('fileimagesloaded'); |
||
2367 | if (!self.resizeImage) { |
||
2368 | return; |
||
2369 | } |
||
2370 | errFunc = self.isUploadable ? self.showUploadError : self.showError; |
||
2371 | for (i = 0; i < self.loadedImages.length; i++) { |
||
2372 | config = self.loadedImages[i]; |
||
2373 | $img = config.img; |
||
2374 | $thumb = config.thumb; |
||
2375 | pid = config.pid; |
||
2376 | ind = config.ind; |
||
2377 | params = {id: pid, 'index': ind}; |
||
2378 | if (!self.getResizedImage($img[0], config.typ, pid, ind)) { |
||
2379 | errFunc(self.msgImageResizeError, params, 'fileimageresizeerror'); |
||
2380 | self.setThumbStatus($thumb, 'Error'); |
||
2381 | self.updateStack(ind, undefined); |
||
2382 | } |
||
2383 | } |
||
2384 | self.raise('fileimagesresized'); |
||
2385 | }, |
||
2386 | getResizedImage: function (image, type, pid, ind) { |
||
2387 | var self = this, width = image.naturalWidth, height = image.naturalHeight, ratio = 1, |
||
2388 | maxWidth = self.maxImageWidth || width, maxHeight = self.maxImageHeight || height, |
||
2389 | isValidImage = (width && height), chkWidth, chkHeight, |
||
2390 | canvas = self.imageCanvas, context = self.imageCanvasContext; |
||
2391 | if (!isValidImage) { |
||
2392 | return false; |
||
2393 | } |
||
2394 | if (width === maxWidth && height === maxHeight) { |
||
2395 | return true; |
||
2396 | } |
||
2397 | type = type || self.resizeDefaultImageType; |
||
2398 | chkWidth = width > maxWidth; |
||
2399 | chkHeight = height > maxHeight; |
||
2400 | if (self.resizePreference === 'width') { |
||
2401 | ratio = chkWidth ? maxWidth / width : (chkHeight ? maxHeight / height : 1); |
||
2402 | } else { |
||
2403 | ratio = chkHeight ? maxHeight / height : (chkWidth ? maxWidth / width : 1); |
||
2404 | } |
||
2405 | self.resetCanvas(); |
||
2406 | width *= ratio; |
||
2407 | height *= ratio; |
||
2408 | canvas.width = width; |
||
2409 | canvas.height = height; |
||
2410 | try { |
||
2411 | context.drawImage(image, 0, 0, width, height); |
||
2412 | canvas.toBlob(function (blob) { |
||
2413 | self.raise('fileimageresized', [pid, ind]); |
||
2414 | self.filestack[ind] = blob; |
||
2415 | }, type, self.resizeQuality); |
||
2416 | return true; |
||
2417 | } |
||
2418 | catch (err) { |
||
2419 | return false; |
||
2420 | } |
||
2421 | }, |
||
2422 | initCaption: function () { |
||
2423 | var self = this, cap = self.initialCaption || ''; |
||
2424 | if (self.overwriteInitial || isEmpty(cap)) { |
||
2425 | self.$caption.html(''); |
||
2426 | return false; |
||
2427 | } |
||
2428 | self.setCaption(cap); |
||
2429 | return true; |
||
2430 | }, |
||
2431 | setCaption: function (content, isError) { |
||
2432 | var self = this, title, out; |
||
2433 | if (isError) { |
||
2434 | title = $('<div>' + self.msgValidationError + '</div>').text(); |
||
2435 | out = '<span class="' + self.msgValidationErrorClass + '">' + |
||
2436 | self.msgValidationErrorIcon + title + '</span>'; |
||
2437 | } else { |
||
2438 | if (isEmpty(content) || self.$caption.length === 0) { |
||
2439 | return; |
||
2440 | } |
||
2441 | title = $('<div>' + content + '</div>').text(); |
||
2442 | out = self.getLayoutTemplate('icon') + title; |
||
2443 | } |
||
2444 | self.$caption.html(out); |
||
2445 | self.$caption.attr('title', title); |
||
2446 | self.$captionContainer.find('.file-caption-ellipsis').attr('title', title); |
||
2447 | }, |
||
2448 | initBrowse: function ($container) { |
||
2449 | var self = this; |
||
2450 | self.$btnFile = $container.find('.btn-file'); |
||
2451 | self.$btnFile.append(self.$element); |
||
2452 | }, |
||
2453 | createContainer: function () { |
||
2454 | var self = this, |
||
2455 | $container = $(document.createElement("div")) |
||
2456 | .attr({"class": 'file-input file-input-new'}) |
||
2457 | .html(self.renderMain()); |
||
2458 | self.$element.before($container); |
||
2459 | self.initBrowse($container); |
||
2460 | return $container; |
||
2461 | }, |
||
2462 | refreshContainer: function () { |
||
2463 | var self = this, $container = self.$container; |
||
2464 | $container.before(self.$element); |
||
2465 | $container.html(self.renderMain()); |
||
2466 | self.initBrowse($container); |
||
2467 | }, |
||
2468 | renderMain: function () { |
||
2469 | var self = this, dropCss = (self.isUploadable && self.dropZoneEnabled) ? ' file-drop-zone' : 'file-drop-disabled', |
||
2470 | close = !self.showClose ? '' : self.getLayoutTemplate('close'), |
||
2471 | preview = !self.showPreview ? '' : self.getLayoutTemplate('preview') |
||
2472 | .replace(/\{class}/g, self.previewClass) |
||
2473 | .replace(/\{dropClass}/g, dropCss), |
||
2474 | css = self.isDisabled ? self.captionClass + ' file-caption-disabled' : self.captionClass, |
||
2475 | caption = self.captionTemplate.replace(/\{class}/g, css + ' kv-fileinput-caption'); |
||
2476 | return self.mainTemplate.replace(/\{class}/g, self.mainClass) |
||
2477 | .replace(/\{preview}/g, preview) |
||
2478 | .replace(/\{close}/g, close) |
||
2479 | .replace(/\{caption}/g, caption) |
||
2480 | .replace(/\{upload}/g, self.renderButton('upload')) |
||
2481 | .replace(/\{remove}/g, self.renderButton('remove')) |
||
2482 | .replace(/\{cancel}/g, self.renderButton('cancel')) |
||
2483 | .replace(/\{browse}/g, self.renderButton('browse')); |
||
2484 | }, |
||
2485 | renderButton: function (type) { |
||
2486 | var self = this, tmplt = self.getLayoutTemplate('btnDefault'), css = self[type + 'Class'], |
||
2487 | title = self[type + 'Title'], icon = self[type + 'Icon'], label = self[type + 'Label'], |
||
2488 | status = self.isDisabled ? ' disabled' : '', btnType = 'button'; |
||
2489 | switch (type) { |
||
2490 | case 'remove': |
||
2491 | if (!self.showRemove) { |
||
2492 | return ''; |
||
2493 | } |
||
2494 | break; |
||
2495 | case 'cancel': |
||
2496 | if (!self.showCancel) { |
||
2497 | return ''; |
||
2498 | } |
||
2499 | css += ' hide'; |
||
2500 | break; |
||
2501 | case 'upload': |
||
2502 | if (!self.showUpload) { |
||
2503 | return ''; |
||
2504 | } |
||
2505 | if (self.isUploadable && !self.isDisabled) { |
||
2506 | tmplt = self.getLayoutTemplate('btnLink').replace('{href}', self.uploadUrl); |
||
2507 | } else { |
||
2508 | btnType = 'submit'; |
||
2509 | } |
||
2510 | break; |
||
2511 | case 'browse': |
||
2512 | tmplt = self.getLayoutTemplate('btnBrowse'); |
||
2513 | break; |
||
2514 | default: |
||
2515 | return ''; |
||
2516 | } |
||
2517 | css += type === 'browse' ? ' btn-file' : ' fileinput-' + type + ' fileinput-' + type + '-button'; |
||
2518 | if (!isEmpty(label)) { |
||
2519 | label = ' <span class="' + self.buttonLabelClass + '">' + label + '</span>'; |
||
2520 | } |
||
2521 | return tmplt.replace('{type}', btnType) |
||
2522 | .replace('{css}', css) |
||
2523 | .replace('{title}', title) |
||
2524 | .replace('{status}', status) |
||
2525 | .replace('{icon}', icon) |
||
2526 | .replace('{label}', label); |
||
2527 | } |
||
2528 | }; |
||
2529 | |||
2530 | $.fn.fileinput = function (option) { |
||
2531 | if (!hasFileAPISupport() && !isIE(9)) { |
||
2532 | return; |
||
2533 | } |
||
2534 | var args = Array.apply(null, arguments), retvals = []; |
||
2535 | args.shift(); |
||
2536 | this.each(function () { |
||
2537 | var self = $(this), data = self.data('fileinput'), options = typeof option === 'object' && option, |
||
2538 | lang = options.language || self.data('language') || 'en', config = $.fn.fileinput.defaults; |
||
2539 | |||
2540 | if (!data) { |
||
2541 | if (lang !== 'en' && !isEmpty($.fn.fileinputLocales[lang])) { |
||
2542 | $.extend(config, $.fn.fileinputLocales[lang]); |
||
2543 | } |
||
2544 | data = new FileInput(this, $.extend(config, options, self.data())); |
||
2545 | self.data('fileinput', data); |
||
2546 | } |
||
2547 | |||
2548 | if (typeof option === 'string') { |
||
2549 | retvals.push(data[option].apply(data, args)); |
||
2550 | } |
||
2551 | }); |
||
2552 | switch (retvals.length) { |
||
2553 | case 0: |
||
2554 | return this; |
||
2555 | case 1: |
||
2556 | return retvals[0]; |
||
2557 | default: |
||
2558 | return retvals; |
||
2559 | } |
||
2560 | }; |
||
2561 | |||
2562 | $.fn.fileinput.defaults = { |
||
2563 | language: 'en', |
||
2564 | showCaption: true, |
||
2565 | showPreview: true, |
||
2566 | showRemove: true, |
||
2567 | showUpload: true, |
||
2568 | showCancel: true, |
||
2569 | showClose: true, |
||
2570 | showUploadedThumbs: true, |
||
2571 | autoReplace: false, |
||
2572 | mainClass: '', |
||
2573 | previewClass: '', |
||
2574 | captionClass: '', |
||
2575 | mainTemplate: null, |
||
2576 | initialCaption: '', |
||
2577 | initialPreview: [], |
||
2578 | initialPreviewDelimiter: '*$$*', |
||
2579 | initialPreviewConfig: [], |
||
2580 | initialPreviewThumbTags: [], |
||
2581 | previewThumbTags: {}, |
||
2582 | initialPreviewShowDelete: true, |
||
2583 | deleteUrl: '', |
||
2584 | deleteExtraData: {}, |
||
2585 | overwriteInitial: true, |
||
2586 | layoutTemplates: defaultLayoutTemplates, |
||
2587 | previewTemplates: defaultPreviewTemplates, |
||
2588 | allowedPreviewTypes: defaultPreviewTypes, |
||
2589 | allowedPreviewMimeTypes: null, |
||
2590 | allowedFileTypes: null, |
||
2591 | allowedFileExtensions: null, |
||
2592 | defaultPreviewContent: null, |
||
2593 | customLayoutTags: {}, |
||
2594 | customPreviewTags: {}, |
||
2595 | previewSettings: defaultPreviewSettings, |
||
2596 | fileTypeSettings: defaultFileTypeSettings, |
||
2597 | previewFileIcon: '<i class="glyphicon glyphicon-file"></i>', |
||
2598 | previewFileIconClass: 'file-icon-4x', |
||
2599 | previewFileIconSettings: {}, |
||
2600 | previewFileExtSettings: {}, |
||
2601 | buttonLabelClass: 'hidden-xs', |
||
2602 | browseIcon: '<i class="glyphicon glyphicon-folder-open"></i>', |
||
2603 | browseClass: 'btn btn-primary', |
||
2604 | removeIcon: '<i class="glyphicon glyphicon-trash"></i>', |
||
2605 | removeClass: 'btn btn-default', |
||
2606 | cancelIcon: '<i class="glyphicon glyphicon-ban-circle"></i>', |
||
2607 | cancelClass: 'btn btn-default', |
||
2608 | uploadIcon: '<i class="glyphicon glyphicon-upload"></i>', |
||
2609 | uploadClass: 'btn btn-default', |
||
2610 | uploadUrl: null, |
||
2611 | uploadAsync: true, |
||
2612 | uploadExtraData: {}, |
||
2613 | minImageWidth: null, |
||
2614 | minImageHeight: null, |
||
2615 | maxImageWidth: null, |
||
2616 | maxImageHeight: null, |
||
2617 | resizeImage: false, |
||
2618 | resizePreference: 'width', |
||
2619 | resizeQuality: 0.92, |
||
2620 | resizeDefaultImageType: 'image/jpeg', |
||
2621 | maxFileSize: 0, |
||
2622 | minFileCount: 0, |
||
2623 | maxFileCount: 0, |
||
2624 | validateInitialCount: false, |
||
2625 | msgValidationErrorClass: 'text-danger', |
||
2626 | msgValidationErrorIcon: '<i class="glyphicon glyphicon-exclamation-sign"></i> ', |
||
2627 | msgErrorClass: 'file-error-message', |
||
2628 | progressThumbClass: "progress-bar progress-bar-success progress-bar-striped Aktif", |
||
2629 | progressClass: "progress-bar progress-bar-success progress-bar-striped Aktif", |
||
2630 | progressCompleteClass: "progress-bar progress-bar-success", |
||
2631 | previewFileType: 'image', |
||
2632 | zoomIndicator: '<i class="glyphicon glyphicon-zoom-in"></i>', |
||
2633 | elCaptionContainer: null, |
||
2634 | elCaptionText: null, |
||
2635 | elPreviewContainer: null, |
||
2636 | elPreviewImage: null, |
||
2637 | elPreviewStatus: null, |
||
2638 | elErrorContainer: null, |
||
2639 | errorCloseButton: '<span class="close kv-error-close">×</span>', |
||
2640 | slugCallback: null, |
||
2641 | dropZoneEnabled: true, |
||
2642 | dropZoneTitleClass: 'file-drop-zone-title', |
||
2643 | fileActionSettings: {}, |
||
2644 | otherActionButtons: '', |
||
2645 | textEncoding: 'UTF-8', |
||
2646 | ajaxSettings: {}, |
||
2647 | ajaxDeleteSettings: {}, |
||
2648 | showAjaxErrorDetails: true |
||
2649 | }; |
||
2650 | |||
2651 | $.fn.fileinputLocales.en = { |
||
2652 | fileSingle: 'file', |
||
2653 | filePlural: 'files', |
||
2654 | browseLabel: 'Browse …', |
||
2655 | removeLabel: 'Remove', |
||
2656 | removeTitle: 'Clear selected files', |
||
2657 | cancelLabel: 'Cancel', |
||
2658 | cancelTitle: 'Abort ongoing upload', |
||
2659 | uploadLabel: 'Upload', |
||
2660 | uploadTitle: 'Upload selected files', |
||
2661 | msgZoomTitle: 'View details', |
||
2662 | msgZoomModalHeading: 'Detailed Preview', |
||
2663 | msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>.', |
||
2664 | msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload.', |
||
2665 | msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>.', |
||
2666 | msgFileNotFound: 'File "{name}" not found!', |
||
2667 | msgFileSecured: 'Security restrictions prevent reading the file "{name}".', |
||
2668 | msgFileNotReadable: 'File "{name}" is not readable.', |
||
2669 | msgFilePreviewAborted: 'File preview aborted for "{name}".', |
||
2670 | msgFilePreviewError: 'An error occurred while reading the file "{name}".', |
||
2671 | msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.', |
||
2672 | msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.', |
||
2673 | msgUploadAborted: 'The file upload was aborted', |
||
2674 | msgValidationError: 'File Upload Error', |
||
2675 | msgLoading: 'Loading file {index} of {files} …', |
||
2676 | msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.', |
||
2677 | msgSelected: '{n} {files} selected', |
||
2678 | msgFoldersNotAllowed: 'Drag & drop files only! {n} folder(s) dropped were skipped.', |
||
2679 | msgImageWidthSmall: 'Width of image file "{name}" must be at least {size} px.', |
||
2680 | msgImageHeightSmall: 'Height of image file "{name}" must be at least {size} px.', |
||
2681 | msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.', |
||
2682 | msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.', |
||
2683 | msgImageResizeError: 'Could not get the image dimensions to resize.', |
||
2684 | msgImageResizeException: 'Error while resizing the image.<pre>{errors}</pre>', |
||
2685 | dropZoneTitle: 'Drag & drop files here …' |
||
2686 | }; |
||
2687 | |||
2688 | $.extend($.fn.fileinput.defaults, $.fn.fileinputLocales.en); |
||
2689 | |||
2690 | $.fn.fileinput.Constructor = FileInput; |
||
2691 | |||
2692 | /** |
||
2693 | * Convert automatically file inputs with class 'file' |
||
2694 | * into a bootstrap fileinput control. |
||
2695 | */ |
||
2696 | $(document).ready(function () { |
||
2697 | var $input = $('input.file[type=file]'); |
||
2698 | if ($input.length) { |
||
2699 | $input.fileinput(); |
||
2700 | } |
||
2701 | }); |
||
2702 | })); |