PageSourceSearch

https://findacarpark.com.au/js/fileinput.js

js findacarpark.com.au collected 2026-10-08 10:24:14 UTC 41,957 bytes, 844 lines download raw bytes

1/*!
2 * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014
3 * @version 2.7.0
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.
11 * 
12 * Author: Kartik Visweswaran
13 * Copyright: 2014, Kartik Visweswaran, Krajee.com
14 * For more JQuery plugins visit http://plugins.krajee.com
15 * For more Yii related demos visit http://demos.krajee.com
16 */
17(function ($) {
18    var STYLE_SETTING = 'style="width:{width};height:{height};"';
19    var PREVIEW_LABEL = '   <div class="text-center"><small>{caption}</small></div>\n';
20    var OBJECT_PARAMS = '      <param name="controller" value="true" />\n' +
21        '      <param name="allowFullScreen" value="true" />\n' +
22        '      <param name="allowScriptAccess" value="always" />\n' +
23        '      <param name="autoPlay" value="false" />\n' +
24        '      <param name="autoStart" value="false" />\n'+
25        '      <param name="quality" value="high" />\n';
26
27    var DEFAULT_PREVIEW = '<div class="file-preview-other" ' + STYLE_SETTING + '>\n' +
28        '       <h2><i class="glyphicon glyphicon-file"></i></h2>\n' +
29        '   </div>';
30    var defaultLayoutTemplates = {
31        main1: '{preview}\n' +
32            '<div class="input-group {class}">\n' +
33            '   {caption}\n' +
34            '   <div class="input-group-btn">\n' +
35            '       {remove}\n' +
36            '       {upload}\n' +
37            '       {browse}\n' +
38            '   </div>\n' +
39            '</div>',
40        main2: '{preview}\n{remove}\n{upload}\n{browse}\n',
41        preview: '<div class="file-preview {class}">\n' +
42            '   <div class="close fileinput-remove text-right">&times;</div>\n' +
43            '   <div class="file-preview-thumbnails"></div>\n' +
44            '   <div class="clearfix"></div>' +
45            '   <div class="file-preview-status text-center text-success"></div>\n' +
46            '   <div class="kv-fileinput-error"></div>\n' +
47            '</div>',
48        caption: '<div tabindex="-1" class="form-control file-caption {class}">\n' +
49            '   <span class="glyphicon glyphicon-file kv-caption-icon"></span><div class="file-caption-name"></div>\n' +
50            '</div>',
51        modal: '<div id="{id}" class="modal fade">\n' +
52            '  <div class="modal-dialog modal-lg">\n' +
53            '    <div class="modal-content">\n' +
54            '      <div class="modal-header">\n' +
55            '        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>\n' +
56            '        <h3 class="modal-title">Detailed Preview <small>{title}</small></h3>\n' +
57            '      </div>\n' +
58            '      <div class="modal-body">\n' +
59            '        <textarea class="form-control" style="font-family:Monaco,Consolas,monospace; height: {height}px;" readonly>{body}</textarea>\n' +
60            '      </div>\n' +
61            '    </div>\n' +
62            '  </div>\n' +
63            '</div>\n'    
64    };
65    var defaultPreviewTypes = ['image', 'html', 'text', 'video', 'audio', 'flash', 'object'];
66    var defaultPreviewTemplates = {
67        generic: '<div class="file-preview-frame" id="{previewId}">\n' +
68            '   {content}\n' +
69            '</div>\n',
70        html: '<div class="file-preview-frame" id="{previewId}">\n' +
71            '    <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
72            '       ' + DEFAULT_PREVIEW + '\n' +
73            '    </object>\n' + PREVIEW_LABEL + 
74            '</div>',
75        image: '<div class="file-preview-frame" id="{previewId}">\n' +
76            '   <img src="{data}" class="file-preview-image" title="{caption}" alt="{caption}" ' + STYLE_SETTING + '>\n' +
77            '</div>\n',
78        text: '<div class="file-preview-frame" id="{previewId}">\n' +
79            '   <div class="file-preview-text" title="{caption}" ' + STYLE_SETTING + '>\n' +
80            '       {data}\n' + 
81            '   </div>\n' + 
82            '</div>\n',
83        video: '<div class="file-preview-frame" id="{previewId}" title="{caption}" ' + STYLE_SETTING + '>\n' +
84            '   <video width="{width}" height="{height}" controls>\n' +
85            '       <source src="{data}" type="{type}">\n' +
86            '       ' + DEFAULT_PREVIEW + '\n' +
87            '   </video>\n' + PREVIEW_LABEL + 
88            '</div>\n',
89        audio: '<div class="file-preview-frame" id="{previewId}" title="{caption}" ' + STYLE_SETTING + '>\n' +
90            '   <audio controls>\n' +
91            '       <source src="{data}" type="{type}">\n' +
92            '       ' + DEFAULT_PREVIEW + '\n' +
93            '   </audio>\n' + PREVIEW_LABEL + 
94            '</div>\n',
95        flash: '<div class="file-preview-frame" id="{previewId}" title="{caption}" ' + STYLE_SETTING + '>\n' +
96            '   <object type="application/x-shockwave-flash" width="{width}" height="{height}" data="{data}">\n' +
97            OBJECT_PARAMS + '       ' + DEFAULT_PREVIEW + '\n' +
98            '   </object>\n' + PREVIEW_LABEL + 
99            '</div>\n',
100        object: '<div class="file-preview-frame" id="{previewId}" title="{caption}" ' + STYLE_SETTING + '>\n' +
101            '    <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
102            '      <param name="movie" value="{caption}" />\n' +
103            OBJECT_PARAMS + '           ' + DEFAULT_PREVIEW + '\n' +
104            '   </object>\n' + PREVIEW_LABEL + 
105            '</div>',
106        other: '<div class="file-preview-frame" id="{previewId}" title="{caption}" ' + STYLE_SETTING + '>\n' +
107            '   ' + DEFAULT_PREVIEW + '\n' + PREVIEW_LABEL + 
108            '</div>',
109    };
110    var defaultPreviewSettings = {
111        image: {width: "100%", height: "160px"},
112        html: {width: "320px", height: "180px"},
113        text: {width: "160px", height: "160px"},
114        video: {width: "320px", height: "240px"},
115        audio: {width: "320px", height: "80px"},
116        flash: {width: "320px", height: "240px"},
117        object: {width: "320px", height: "300px"},
118        other: {width: "160px", height: "120px"}
119    };
120    var defaultFileTypeSettings = {
121        image: function(vType, vName) {
122            return (typeof vType !== "undefined") ? vType.match('image.*') : vName.match(/\.(gif|png|jpe?g)$/i);
123        },
124        html: function(vType, vName) {
125            return (typeof vType !== "undefined") ? vType == 'text/html' : vName.match(/\.(htm|html)$/i);
126        },
127        text: function(vType, vName) {
128            return typeof vType !== "undefined" && vType.match('text.*') || vName.match(/\.(txt|md|csv|nfo|php|ini)$/i);
129        },
130        video: function (vType, vName) {
131            return typeof vType !== "undefined" && vType.match(/\.video\/(ogg|mp4|webm)$/i) || vName.match(/\.(og?|mp4|webm)$/i);
132        },
133        audio: function (vType, vName) {
134            return typeof vType !== "undefined" && vType.match(/\.audio\/(ogg|mp3|wav)$/i) || vName.match(/\.(ogg|mp3|wav)$/i);
135        },
136        flash: function (vType, vName) {
137            return typeof vType !== "undefined" && vType == 'application/x-shockwave-flash' || vName.match(/\.(swf)$/i);
138        },
139        object: function (vType, vName) {
140            return true;
141        },
142        other: function (vType, vName) {
143            return true;
144        },
145    };
146    var isEmpty = function (value, trim) {
147            return value === null || value === undefined || value == []
148            || value === '' || trim && $.trim(value) === '';
149        },
150        isArray = function (a) {
151            return Array.isArray(a) || Object.prototype.toString.call(a) === '[object Array]';
152        },
153        isSet = function (needle, haystack) {
154            return (typeof haystack == 'object' && needle in haystack);
155        },
156        getValue = function (options, param, value) {
157            return (isEmpty(options) || isEmpty(options[param])) ? value : options[param];
158        },
159        getElement = function (options, param, value) {
160            return (isEmpty(options) || isEmpty(options[param])) ? value : $(options[param]);
161        },
162        uniqId = function () {
163            return Math.round(new Date().getTime() + (Math.random() * 100));
164        },
165        hasFileAPISupport = function () {
166            return window.File && window.FileReader && window.FileList && window.Blob;
167        },
168        htmlEncode = function(str) {
169            return String(str)
170                .replace(/&/g, '&amp;')
171                .replace(/"/g, '&quot;')
172                .replace(/'/g, '&#39;')
173                .replace(/</g, '&lt;')
174                .replace(/>/g, '&gt;');
175        },
176        vUrl = window.URL || window.webkitURL;
177
178    var FileInput = function (element, options) {
179        this.$element = $(element);
180        if (hasFileAPISupport()) {
181            this.init(options);
182            this.listen();
183        } else {
184            this.$element.removeClass('file-loading');
185        }
186    };
187
188    FileInput.prototype = {
189        constructor: FileInput,
190        init: function (options) {
191            var self = this;
192            self.reader = null;
193            self.showCaption = options.showCaption;
194            self.showPreview = options.showPreview;
195            self.maxFileSize = options.maxFileSize;
196            self.maxFileCount = options.maxFileCount;
197            self.msgSizeTooLarge = options.msgSizeTooLarge;
198            self.msgFilesTooMany = options.msgFilesTooMany;
199            self.msgFileNotFound = options.msgFileNotFound;
200            self.msgFileNotReadable = options.msgFileNotReadable;
201            self.msgFilePreviewAborted = options.msgFilePreviewAborted;
202            self.msgFilePreviewError = options.msgFilePreviewError;
203            self.msgValidationError = options.msgValidationError;
204            self.msgErrorClass = options.msgErrorClass;
205            self.initialDelimiter = options.initialDelimiter;
206            self.initialPreview = options.initialPreview;
207            self.initialCaption = options.initialCaption;
208            self.initialPreviewCount = options.initialPreviewCount;
209            self.initialPreviewContent = options.initialPreviewContent;
210            self.overwriteInitial = options.overwriteInitial;
211            self.layoutTemplates = options.layoutTemplates;
212            self.previewTemplates = options.previewTemplates;
213            self.allowedPreviewTypes = isEmpty(options.allowedPreviewTypes) ? defaultPreviewTypes : options.allowedPreviewTypes;
214            self.allowedPreviewMimeTypes = options.allowedPreviewMimeTypes;
215            self.allowedFileTypes = options.allowedFileTypes;
216            self.allowedFileExtensions = options.allowedFileExtensions;
217            self.previewSettings = options.previewSettings;
218            self.fileTypeSettings = options.fileTypeSettings;
219            self.showRemove = options.showRemove;
220            self.showUpload = options.showUpload;
221            self.captionClass = options.captionClass;
222            self.previewClass = options.previewClass;
223            self.mainClass = options.mainClass;
224            self.mainTemplate = self.showCaption ? self.getLayoutTemplate('main1') : self.getLayoutTemplate('main2');
225            self.captionTemplate = self.getLayoutTemplate('caption');
226            self.previewGenericTemplate = self.getPreviewTemplate('generic');
227            self.browseLabel = options.browseLabel;
228            self.browseIcon = options.browseIcon;
229            self.browseClass = options.browseClass;
230            self.removeLabel = options.removeLabel;
231            self.removeIcon = options.removeIcon;
232            self.removeClass = options.removeClass;
233            self.uploadLabel = options.uploadLabel;
234            self.uploadIcon = options.uploadIcon;
235            self.uploadClass = options.uploadClass;
236            self.uploadUrl = options.uploadUrl;
237            self.msgLoading = options.msgLoading;
238            self.msgProgress = options.msgProgress;
239            self.msgSelected = options.msgSelected;
240            self.msgInvalidFileType = options.msgInvalidFileType;
241            self.msgInvalidFileExtension = options.msgInvalidFileExtension;
242            self.previewFileType = options.previewFileType;
243            self.wrapTextLength = options.wrapTextLength;
244            self.wrapIndicator = options.wrapIndicator;
245            self.isError = false;
246            self.isDisabled = self.$element.attr('disabled') || self.$element.attr('readonly');
247            if (isEmpty(self.$element.attr('id'))) {
248                self.$element.attr('id', uniqId());
249            }
250            if (typeof self.$container == 'undefined') {
251                self.$container = self.createContainer();
252            } else {
253                self.refreshContainer();
254            }
255            self.$captionContainer = getElement(options, 'elCaptionContainer', self.$container.find('.file-caption'));
256            self.$caption = getElement(options, 'elCaptionText', self.$container.find('.file-caption-name'));
257            self.$previewContainer = getElement(options, 'elPreviewContainer', self.$container.find('.file-preview'));
258            self.$preview = getElement(options, 'elPreviewImage', self.$container.find('.file-preview-thumbnails'));
259            self.$previewStatus = getElement(options, 'elPreviewStatus', self.$container.find('.file-preview-status'));
260            self.$errorContainer = getElement(options, 'elErrorContainer', self.$previewContainer.find('.kv-fileinput-error'));
261            if (!isEmpty(self.msgErrorClass)) { 
262                self.$errorContainer.removeClass(self.msgErrorClass).addClass(self.msgErrorClass);
263            }
264            self.$errorContainer.hide();
265            var content = self.initialPreview;
266            self.initialPreviewCount = isArray(content) ? content.length : (content.length > 0 ? content.split(self.initialDelimiter).length : 0)
267            self.initPreview();
268            self.original = {
269                preview: self.$preview.html(),
270                caption: self.$caption.html()
271            };
272            self.options = options;
273            self.$element.removeClass('file-loading');
274        },
275        getLayoutTemplate: function(t) {
276            var self = this;
277            return isSet(t, self.layoutTemplates) ? self.layoutTemplates[t] : defaultLayoutTemplates[t];
278        },
279        getPreviewTemplate: function(t) {
280            var self = this;
281            return isSet(t, self.previewTemplates) ? self.previewTemplates[t] : defaultPreviewTemplates[t];
282        },
283        listen: function () {
284            var self = this, $el = self.$element, $cap = self.$captionContainer, $btnFile = self.$btnFile;
285            $el.on('change', $.proxy(self.change, self));
286            $btnFile.on('click', function (ev) {
287                self.clear(false);
288                $cap.focus();
289            });
290            $el.closest('form').on('reset', $.proxy(self.reset, self));
291            self.$container.on('click', '.fileinput-remove:not([disabled])', $.proxy(self.clear, self));
292        },
293        refresh: function (options) {
294            var self = this, params = (arguments.length) ? $.extend(self.options, options) : self.options;
295            self.$element.off();
296            self.init(params);
297        },
298        initPreview: function () {
299            var self = this, html = '', content = self.initialPreview, len = self.initialPreviewCount,
300                cap = self.initialCaption.length, previewId = "preview-" + uniqId(),
301                caption = (cap > 0) ? self.initialCaption : self.msgSelected.replace(/\{n\}/g, len),
302                title = $(caption).text();
303            if (isArray(content) && len > 0) {
304                for (var i = 0; i < len; i++) {
305                    previewId += '-' + i;
306                    html += self.previewGenericTemplate.replace(/\{previewId\}/g, previewId).replace(/\{content\}/g,
307                        content[i]);
308                }
309                if (len > 1 && cap == 0) {
310                    caption = self.msgSelected.replace(/\{n\}/g, len);
311                }
312            } else {
313                if (len > 0) {
314                    var fileList = content.split(self.initialDelimiter);
315                    for (var i = 0; i < len; i++) {
316                        previewId += '-' + i;
317                        html += self.previewGenericTemplate.replace(/\{previewId\}/g, previewId).replace(/\{content\}/g,
318                            fileList[i]);
319                    }
320                    if (len > 1 && cap == 0) {
321                        caption = self.msgSelected.replace(/\{n\}/g, len);
322                    }
323                } else {
324                    if (cap > 0) {
325                        self.$caption.html(caption);
326                        self.$captionContainer.attr('title', title);
327                        return;
328                    } else {
329                        return;
330                    }
331                }
332            }
333            self.initialPreviewContent = html;
334            self.$preview.html(html);
335            self.$caption.html(caption);
336            self.$captionContainer.attr('title', title);
337            self.$container.removeClass('file-input-new');
338        },
339        clearObjects: function() {
340            var self = this, $preview = self.$preview;
341            $preview.find('video audio').each(function() {
342                 this.pause();
343                 delete(this);
344                 $(this).remove();
345            });
346            $preview.find('img object div').each(function() {
347                delete(this);
348                $(this).remove();
349            });
350        },
351        clearFileInput: function() {
352            var self = this, $el = self.$element;
353            if (isEmpty($el.val())) {
354                return;
355            }
356            // Fix for IE ver < 11, that does not clear file inputs
357            // Requires a sequence of steps to prevent IE crashing but
358            // still allow clearing of the file input.
359            if (/MSIE/.test(navigator.userAgent)) {
360                var $frm1 = $el.closest('form');
361                if ($frm1.length) {
362                    $el.wrap('<form>');
363                    var $frm2 = $el.closest('form'), $tmpEl = $(document.createElement('div'));
364                    $frm2.before($tmpEl).after($frm1).trigger('reset');
365                    $el.unwrap().appendTo($tmpEl).unwrap();
366                } else {
367                    $el.wrap('<form>').closest('form').trigger('reset').unwrap();
368                }   
369            } else { // normal input clear behavior for other sane browsers
370                $el.val('');
371            }
372        },
373        clear: function () {
374            var self = this, e = arguments.length && arguments[0];
375            if (e) {
376                e.preventDefault();
377            }
378            if (self.reader instanceof FileReader) {
379                self.reader.abort();
380            }
381            self.clearFileInput();
382            self.resetErrors(true);
383            
384            if (e !== false) {
385                self.$element.trigger('change');
386                self.$element.trigger('fileclear');
387            }
388            if (self.overwriteInitial) {
389                self.initialPreviewCount = 0;
390            }
391            if (!self.overwriteInitial && !isEmpty(self.initialPreviewContent)) {
392                self.showFileIcon();
393                self.$preview.html(self.original.preview);
394                self.$caption.html(self.original.caption);
395                self.$container.removeClass('file-input-new');
396            } else {
397                self.clearObjects();
398                self.$preview.html('');
399                var cap = (!self.overwriteInitial && self.initialCaption.length > 0) ?
400                    self.original.caption : '';
401                self.$caption.html(cap);
402                self.$captionContainer.attr('title', '');
403                self.$container.removeClass('file-input-new').addClass('file-input-new');
404            }
405            self.hideFileIcon();
406            self.$element.trigger('filecleared');
407            self.$captionContainer.focus();
408        },
409        reset: function (e) {
410            var self = this;
411            self.clear(false);
412            self.$preview.html(self.original.preview);
413            self.$caption.html(self.original.caption);
414            self.$container.find('.fileinput-filename').text('');
415            self.$element.trigger('filereset');
416            if (self.initialPreview.length > 0) {
417                self.$container.removeClass('file-input-new');
418            }
419        },
420        disable: function (e) {
421            var self = this;
422            self.isDisabled = true;
423            self.$element.attr('disabled', 'disabled');
424            self.$container.find(".kv-fileinput-caption").addClass("file-caption-disabled");
425            self.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload").attr("disabled", true);
426        },
427        enable: function (e) {
428            var self = this;
429            self.isDisabled = false;
430            self.$element.removeAttr('disabled');
431            self.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled");
432            self.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload").removeAttr("disabled");
433        },
434        hideFileIcon: function () {
435            if (this.overwriteInitial) {
436                this.$captionContainer.find('.kv-caption-icon').hide();
437            }
438        },
439        showFileIcon: function () {
440            this.$captionContainer.find('.kv-caption-icon').show();
441        },
442        resetErrors: function (fade) {
443            var self = this, $error = self.$errorContainer;
444            self.isError = false;
445            self.$container.removeClass('has-error');
446            if (fade) {
447                $error.fadeOut('slow');
448            } else {
449                $error.hide();
450            }
451        },
452        showError: function (msg, file, previewId, index) {
453            var self = this, $error = self.$errorContainer, $el = self.$element;
454            $error.html(msg);
455            $error.fadeIn(800);
456            $el.trigger('fileerror', [file, previewId, index]);
457            self.clearFileInput();
458            self.$container.removeClass('has-error').addClass('has-error');
459            return true;
460        },
461        errorHandler: function (evt, caption) {
462            var self = this;
463            switch (evt.target.error.code) {
464                case evt.target.error.NOT_FOUND_ERR:
465                    self.addError(self.msgFileNotFound.replace(/\{name\}/g, caption));
466                    break;
467                case evt.target.error.NOT_READABLE_ERR:
468                    self.addError(self.msgFileNotReadable.replace(/\{name\}/g, caption));
469                    break;
470                case evt.target.error.ABORT_ERR:
471                    self.addError(self.msgFilePreviewAborted.replace(/\{name\}/g, caption));
472                    break;
473                default:
474                    self.addError(self.msgFilePreviewError.replace(/\{name\}/g, caption));
475            }
476        },
477        parseFileType: function(file) {
478            var isValid, vType;
479            for (var i = 0;
479 i < defaultPreviewTypes.length; i++) {
480                cat = defaultPreviewTypes[i];
481                isValid = isSet(cat, self.fileTypeSettings) ? self.fileTypeSettings[cat] : defaultFileTypeSettings[cat];
482                vType = isValid(file.type, file.name) ? cat : '';
483                if (vType != '') {
484                    return vType;
485                }
486            }
487            return 'other';
488        },
489        previewDefault: function(file, previewId) {
490            var self = this, data = vUrl.createObjectURL(file), $obj = $('#' + previewId),
491                previewOtherTemplate = isSet('other', self.previewTemplates) ? self.previewTemplates['other'] : defaultPreviewTemplates['other'];
492            self.$preview.append("\n" + previewOtherTemplate
493                .replace(/\{previewId\}/g, previewId)
494                .replace(/\{caption\}/g, self.slug(file.name))
495                .replace(/\{type\}/g, file.type)
496                .replace(/\{data\}/g, data));
497            $obj.on('load', function(e) {
498                vUrl.revokeObjectURL($obj.attr('data'));
499            });
500        },
501        previewFile: function(file, theFile, previewId, data) {
502            var self = this, i, cat = self.parseFileType(file), caption = self.slug(file.name), data, obj, content, 
503                types = self.allowedPreviewTypes, mimes = self.allowedPreviewMimeTypes, fType = file.type, 
504                template = isSet(cat, self.previewTemplates) ? self.previewTemplates[cat] : defaultPreviewTemplates[cat], 
505                config = isSet(cat, self.previewSettings) ? self.previewSettings[cat] : defaultPreviewSettings[cat],
506                wrapLen = parseInt(self.wrapTextLength), wrapInd = self.wrapIndicator, $preview = self.$preview, 
507                chkTypes = types.indexOf(cat) >=0, chkMimes = isEmpty(mimes) || (!isEmpty(mimes) && isSet(file.type, mimes));
508            if (chkTypes && chkMimes) {
509                if (cat == 'text') {
510                    var strText = htmlEncode(theFile.target.result);
511                    vUrl.revokeObjectURL(data);
512                    if (strText.length > wrapLen) {
513                        var id = 'text-' + uniqId(), height = window.innerHeight * .75,
514                            modal = self.getLayoutTemplate('modal')
515                                .replace(/\{id\}/g, id)
516                                .replace(/\{title\}/g, caption)
517                                .replace(/\{height\}/g, height)
518                                .replace(/\{body\}/g, strText);
519                            wrapInd = wrapInd
520                                .replace(/\{title\}/g, caption)
521                                .replace(/\{dialog\}/g, "$('#" + id + "').modal('show')");
522                            strText = strText.substring(0, (wrapLen - 1)) + wrapInd;
523                    }
524                    content = template
525                        .replace(/\{previewId\}/g, previewId).replace(/\{caption\}/g, caption)
526                        .replace(/\{type\}/g, file.type).replace(/\{width\}/g, config.width)
527                        .replace(/\{height\}/g, config.height).replace(/\{data\}/g, strText) + modal;
528                } else {
529                    content = template
530                        .replace(/\{previewId\}/g, previewId).replace(/\{caption\}/g, caption)
531                        .replace(/\{type\}/g, file.type).replace(/\{data\}/g, data)
532                        .replace(/\{width\}/g, config.width).replace(/\{height\}/g, config.height);
533                }
534                $preview.append("\n" + content);
535            } else {
536                self.previewDefault(file, previewId);
537            }
538        },
539        readFiles: function (files) {
540            this.reader = new FileReader();
541            var self = this, $el = self.$element, $preview = self.$preview, reader = self.reader,
542                $container = self.$previewContainer, $status = self.$previewStatus, msgLoading = self.msgLoading,
543                msgProgress = self.msgProgress, msgSelected = self.msgSelected, fileType = self.previewFileType,
544                wrapLen = parseInt(self.wrapTextLength), wrapInd = self.wrapIndicator,
545                previewInitId = "preview-" + uniqId(), numFiles = files.length, settings = self.fileTypeSettings,
546                isText = isSet('text', settings) ? settings['text'] : defaultFileTypeSettings['text'];
547
548            function readFile(i) {
549                if (i >= numFiles) {
550                    $container.removeClass('loading');
551                    $status.html('');
552                    return;
553                }
554                var previewId = previewInitId + "-" + i, file = files[i], caption = self.slug(file.name), 
555                    fileSize = (file.size ? file.size : 0) / 1000, checkFile, 
556                    previewData = vUrl.createObjectURL(file), fileCount = 0, j, msg, typ, chk,
557                    fileTypes = self.allowedFileTypes, strTypes = isEmpty(fileTypes) ? '' : fileTypes.join(', '), 
558                    fileExt = self.allowedFileExtensions, strExt = isEmpty(fileExt) ? '' : fileExt.join(', '),
559                    fileExtExpr = isEmpty(fileExt) ? '' : new RegExp('\\.(' + fileExt.join('|') + ')$', 'i');
560                fileSize = fileSize.toFixed(2);
561                if (self.maxFileSize > 0 && fileSize > self.maxFileSize) {
562                    msg = self.msgSizeTooLarge.replace(/\{name\}/g, caption).replace(/\{size\}/g,
563                        fileSize).replace(/\{maxSize\}/g, self.maxFileSize);
564                    self.isError = self.showError(msg, file, previewId, i);
565                    return;
566                }
567                if (!isEmpty(fileTypes) && isArray(fileTypes)) {
568                    for (j = 0; j < fileTypes.length; j++) {
569                        typ = fileTypes[j];
570                        checkFile = settings[typ];
571                        chk = (checkFile !== undefined && checkFile(file.type, caption));
572                        fileCount += isEmpty(chk) ? 0 : chk.length;
573                    }
574                    if (fileCount == 0) {
575                        msg = self.msgInvalidFileType.replace(/\{name\}/g, caption).replace(/\{types\}/g, strTypes);
576                        self.isError = self.showError(msg, file, previewId, i);
577                        return;
578                    }
579                }
580                if (fileCount == 0 && !isEmpty(fileExt) && isArray(fileExt) && !isEmpty(fileExtExpr)) {
581                    chk = caption.match(fileExtExpr);
582                    fileCount += isEmpty(chk) ? 0 : chk.length;
583                    if (fileCount == 0) {
584                        msg = self.msgInvalidFileExtension.replace(/\{name\}/g, caption).replace(/\{extensions\}/g, strExt);
585                        self.isError = self.showError(msg, file, previewId, i);
586                        return;
587                    }
588                }
589                if (!self.showPreview) {
590                    $el.trigger('fileloaded', [file, previewId, i]);
591                    setTimeout(readFile(i + 1), 1000);
592                    return;
593                }
594                if ($preview.length > 0 && typeof FileReader !== "undefined") {
595                    $status.html(msgLoading.replace(/\{index\}/g, i + 1).replace(/\{files\}/g, numFiles));
596                    $container.addClass('loading');
597                    reader.onerror = function (evt) {
598                        self.errorHandler(evt, caption);
599                    };
600                    reader.onload = function (theFile) {
601                        self.previewFile(file, theFile, previewId, previewData);
602                    };
603                    reader.onloadend = function (e) {
604                        var msg = msgProgress
605                            .replace(/\{index\}/g, i + 1).replace(/\{files\}/g, numFiles)
606                            .replace(/\{percent\}/g, 100).replace(/\{name\}/g, caption);
607                        setTimeout(function () {
608                            $status.html(msg);
609                            vUrl.revokeObjectURL(previewData);
610                        }, 1000);
611                        setTimeout(function () {
612                            readFile(i + 1);
613                        }, 1500);
614                        $el.trigger('fileloaded', [file, previewId, i]);
615                    };
616                    reader.onprogress = function (data) {
617                        if (data.lengthComputable) {
618                            var progress = parseInt(((data.loaded / data.total) * 100), 10);
619                            var msg = msgProgress
620                                .replace(/\{index\}/g, i + 1).replace(/\{files\}/g, numFiles)
621                                .replace(/\{percent\}/g, progress).replace(/\{name\}/g, caption);
622                            setTimeout(function () {
623                                $status.html(msg);
624                            }, 1000);
625                        }
626                    };
627                    if (isText(file.type, caption)) {
628                        reader.readAsText(file);
629                    } else {
630                        reader.readAsArrayBuffer(file);
631                    }
632                } else {
633                    self.previewDefault(file, previewId);
634                    $el.trigger('fileloaded', [file, previewId, i]);
635                    setTimeout(readFile(i + 1), 1000);
636                }
637            }
638            readFile(0);
639        },
640        slug: function (text) {
641            return isEmpty(text) ? '' : text.split(/(\\|\/)/g).pop().replace(/[^\w-.\\\/ ]+/g,'');
642        },
643        change: function (e) {
644            var self = this, $el = self.$element, label = self.slug($el.val()),
645                total = 0, $preview = self.$preview, files = $el.get(0).files, msgSelected = self.msgSelected,
646                numFiles = !isEmpty(files) ? (files.length + self.initialPreviewCount) : 1, tfiles;
647            self.hideFileIcon();
648            if (e.target.files === undefined) {
649                tfiles = e.target && e.target.value ? [
650                    {name: e.target.value.replace(/^.+\\/, '')}
651                ] : [];
652            } else {
653                tfiles = e.target.files;
654            }
655            if (tfiles.length === 0) {
656                return;
657            }
658            self.resetErrors();
659            $preview.html('');
660            if (!self.overwriteInitial) {
661                $preview.html(self.initialPreviewContent);
662            }
663            var total = tfiles.length;
664            if (self.maxFileCount > 0 && total > self.maxFileCount) {
665                var msg = self.msgFilesTooMany.replace(/\{m\}/g, self.maxFileCount).replace(/\{n\}/g, total);
666                self.isError = self.showError(msg, null, null, null);
667                self.$captionContainer.find('.kv-caption-icon').hide();
668                self.$caption.html(self.msgValidationError);
669                self.$container.removeClass('file-input-new');
670                return;
671            }
672            self.readFiles(files);
673            self.reader = null;
674            var log = numFiles > 1 ? msgSelected.replace(/\{n\}/g, numFiles) : label;
675            if (self.isError) {
676                self.$captionContainer.find('.kv-caption-icon').hide();
677                log = self.msgValidationError;
678            } else {
679                self.showFileIcon();
680            }
681            self.$caption.html(log);
682            self.$captionContainer.attr('title', $(log).text());
683            self.$container.removeClass('file-input-new');
684            $el.trigger('fileselect', [numFiles, label]);
685        },
686        initBrowse: function ($container) {
687            var self = this;
688            self.$btnFile = $container.find('.btn-file');
689            self.$btnFile.append(self.$element);
690        },
691        createContainer: function () {
692            var self = this;
693            var $container = $(document.createElement("span")).attr({"class": 'file-input file-input-new'}).html(self.renderMain());
694            self.$element.before($container);
695            self.initBrowse($container);
696            return $container;
697        },
698        refreshContainer: function () {
699            var self = this, $container = self.$container;
700            $container.before(self.$element);
701            $container.html(self.renderMain());
702            self.initBrowse($container);
703        },
704        renderMain: function () {
705            var self = this;
706            var preview = self.showPreview ? self.getLayoutTemplate('preview').replace(/\{class\}/g, self.previewClass) : '';
707            var css = self.isDisabled ? self.captionClass + ' file-caption-disabled' : self.captionClass;
708            var caption = self.captionTemplate.replace(/\{class\}/g, css + ' kv-fileinput-caption');
709            return self.mainTemplate.replace(/\{class\}/g, self.mainClass).
710                replace(/\{preview\}/g, preview).
711                replace(/\{caption\}/g, caption).
712                replace(/\{upload\}/g, self.renderUpload()).
713                replace(/\{remove\}/g, self.renderRemove()).
714                replace(/\{browse\}/g, self.renderBrowse());
715        },
716        renderBrowse: function () {
717            var self = this, css = self.browseClass + ' btn-file', status = '';
718            if (self.isDisabled) {
719                status = ' disabled ';
720            }
721            return '<div class="' + css + '"' + status + '> ' + self.browseIcon + self.browseLabel + ' </div>';
722        },
723        renderRemove: function () {
724            var self = this, css = self.removeClass + ' fileinput-remove fileinput-remove-button', status = '';
725            if (!self.showRemove) {
726                return '';
727            }
728            if (self.isDisabled) {
729                status = ' disabled ';
730            }
731            return '<button type="button" class="' + css + '"' + status + '>' + self.removeIcon + self.removeLabel + '</button>';
732        },
733        renderUpload: function () {
734            var self = this, css = self.uploadClass + ' kv-fileinput-upload', content = '', status = '';
735            if (!self.showUpload) {
736                return '';
737            }
738            if (self.isDisabled) {
739                status = ' disabled ';
740            }
741            if (isEmpty(self.uploadUrl)) {
742                content = '<button type="submit" class="' + css + '"' + status + '>' + self.uploadIcon + self.uploadLabel + '</button>';
743            } else {
744                content = '<a href="' + self.uploadUrl + '" class="' + self.uploadClass + '"' + status + '>' + self.uploadIcon + self.uploadLabel + '</a>';
745            }
746            return content;
747        }
748    }
749
750    //FileInput plugin definition
751    $.fn.fileinput = function (option) {
752        if (!hasFileAPISupport()) {
753          return;
754        }
755        
756        var args = Array.apply(null, arguments);
757        args.shift();
758        return this.each(function () {
759            var $this = $(this),
760                data = $this.data('fileinput'),
761                options = typeof option === 'object' && option;
762
763            if (!data) {
764                $this.data('fileinput',
765                    (data = new FileInput(this, $.extend({}, $.fn.fileinput.defaults, options, $(this).data()))));
766            }
767
768            if (typeof option === 'string') {
769                data[option].apply(data, args);
770            }
771        });
772    };
773
774    $.fn.fileinput.defaults = {
775        showCaption: true,
776        showPreview: true,
777        showRemove: true,
778        showUpload: true,
779        mainClass: '',
780        previewClass: '',
781        captionClass: '',
782        mainTemplate: null,
783        initialDelimiter: '*$$*',
784        initialPreview: '',
785        initialCaption: '',
786        initialPreviewCount: 0,
787        initialPreviewContent: '',
788        overwriteInitial: true,
789        layoutTemplates: defaultLayoutTemplates,
790        previewTemplates: defaultPreviewTemplates,
791        allowedPreviewTypes: defaultPreviewTypes,
792        allowedPreviewMimeTypes: null,
793        allowedFileTypes: null,
794        allowedFileExtensions: null,
795        previewSettings: defaultPreviewSettings,
796        fileTypeSettings: defaultFileTypeSettings,
797        browseLabel: 'Browse &hellip;',
798        browseIcon: '<i class="glyphicon glyphicon-folder-open"></i> &nbsp;',
799        browseClass: 'btn btn-primary',
800        removeLabel: 'Remove',
801        removeIcon: '<i class="glyphicon glyphicon-ban-circle"></i> ',
802        removeClass: 'btn btn-default',
803        uploadLabel: 'Upload',
804        uploadIcon: '<i class="glyphicon glyphicon-upload"></i> ',
805        uploadClass: 'btn btn-default',
806        uploadUrl: null,
807        maxFileSize: 0,
808        maxFileCount: 0,
809        msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>. Please retry your upload!',
810        msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>. Please retry your upload!',
811        msgFileNotFound: 'File "{name}" not found!',
812        msgFileNotReadable: 'File "{name}" is not readable.',
813        msgFilePreviewAborted: 'File preview aborted for "{name}".',
814        msgFilePreviewError: 'An error occurred while reading the file "{name}".',
815        msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.',
816        msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.',
817        msgValidationError: '<span class="text-danger"><i class="glyphicon glyphicon-exclamation-sign"></i> File Upload Error</span>',
818        msgErrorClass: 'file-error-message',
819        msgLoading: 'Loading  file {index} of {files} &hellip;',
820        msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.',
821        msgSelected: '{n} files selected',
822        previewFileType: 'image',
823        wrapTextLength: 250,
824        wrapIndicator: ' <span class="wrap-indicator" title="{title}" onclick="{dialog}">[&hellip;]</span>',
825        elCaptionContainer: null,
826        elCaptionText: null,
827        elPreviewContainer: null,
828        elPreviewImage: null,
829        elPreviewStatus: null,
830        elErrorContainer: null        
831    };
832
833    /**
834     * Convert automatically file inputs with class 'file'
835     * into a bootstrap fileinput control.
836     */
837    $(document).ready(function () {
838        var $input = $('input.file[type=file]'), count = $input.attr('type') != null ? $input.length : 0;
839        if (count > 0) {
840            $input.fileinput();
841        }
842    });
843
844})(window.jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.