PageSourceSearch

https://www.openstm32.org/lib/jquery_tiki/files.js

js openstm32.org collected 2026-10-04 00:01:16 UTC 39,130 bytes, 1,044 lines download raw bytes

1
2(function ($) {
3    var handleFiles, ProgressBar, FileList, FileListInline;
4
5    $.fileTypeIcon = function (fileId, file) {
6        var themeIconset = jqueryTiki.themeIconset;
7
8        if (typeof file.type == 'undefined') {
9            return getIcon(themeIconset, "undefined");
10        } else if(file.type.substring(0,6) == 'image/') {
11            return $('<img src="tiki-download_file.php?fileId=' + fileId + '&display&y=24" height="24">');
12        } else if(file.type == 'application/pdf') {
13            return getIcon(themeIconset, file.type, "pdf", "pdf");
14        } else if(file.type.indexOf("sheet") != -1 || file.type.indexOf("excel") != -1) {
15            return getIcon(themeIconset, file.type, "excel", "xls");
16        } else if(file.type.indexOf("zip") != -1) {
17            return getIcon(themeIconset, file.type, "zip", "zip");
18        } else if (file.type.substring(0,6) == 'video/') {
19            return getIcon(themeIconset, file.type, "video", "flv");
20        } else if (file.type.indexOf("word") != -1) {
21            return getIcon(themeIconset, file.type, "word", "doc");
22        } else {
23            return getIcon(themeIconset, file.type);
24        }
25    };
26
27    ProgressBar = function (options) {
28        var bar = this;
29        this.segments = [];
30        this.updateSegment = function (number, current, total) {
31            bar.segments[number] = [current, total];
32            bar.update();
33        };
34        this.update = function () {
35            var total = 0, current = 0;
36            $.each(bar.segments, function (k, item) {
37                current += item[0];
38                total += item[1];
39            });
40
41            options.progress(current, total);
42
43            if (current === total) {
44                options.done();
45            }
46        };
47    };
48
49    FileList = function (options) {
50        var $list = $(options.list);
51
52        this.list = $list;
53        this.clearErrors = function () {
54            $list.find('.text-danger').remove();
55        };
56        this.addError = function (file, message) {
57            var $li = $('<li>').appendTo($list);
58
59            $li.text(file.name);
60            $li.addClass('text-danger');
61            $li.append(' (' + (message ? message : tr('uploading failed')) + ')');
62        };
63        this.addFile = function (fileId, file, title) {
64            // called for "upload in modal" tracker Files fields when file dropped or picked from the file dialog
65            var $li = $('<li>').addClass("row mb-4").appendTo($list);
66
67            var label = file.name;
68            if (title) {
69                label = title;
70            }
71            if ($list.data("changefilename")) {
72                $("<div>").addClass("col-2 change-file")
73                    .append($.fileTypeIcon(fileId, file).css("margin-right", "1em"))
74                    .appendTo($li);
75                var labelNewFileName = title ? title : label.replace(/\.[^.]*$/,''); //Remove extension from file name
76                $("<div>").addClass("col-10 input-text" + fileId + "").append($('<input type="text" class="form-control newfilename ' + fileId + '" name="newfilename[]">')
77                .attr('value', labelNewFileName))
78                    .appendTo($li);
79            } else {
80                $("<div>").addClass("col-sm-12").text(label)
81                .prepend($.fileTypeIcon(fileId, file).css("margin-right", "1em"))
82                .appendTo($li);
83            }
84
85            if ($list.parents(".inline").length) {
86                var $fileInput = $list.parents(".files-field").find("> input");
87                var val = $fileInput.val();
88                val = val ? val + "," + fileId : fileId;
89                $fileInput.val(val);
90            } else {
91                $('<input type="hidden" name="file[]">')
92                    .attr('value', fileId)
93                    .appendTo($li);
94
95                if ($list.data("adddescription")) {
96                    $("<label>")
97                        .addClass("col-form-label col-sm-4")
98                        .text(tr("Description"))
99                        .appendTo($li);
100                    $("<div>").addClass("col-sm-12")
101                        .append($('<textarea name="description[]">')
102                            .addClass("form-control col-sm-8")
103                        )
104                        .appendTo($li);
105                }
106            }
107
108        };
109    };
110
111    handleFiles = function (input) {
112
113        var files = input.files,
114            accept = input.accept,
115            title = input.title,
116            galleryId = input.galleryId,
117            image_max_size_x = input.image_max_size_x,
118            image_max_size_y = input.image_max_size_y,
119            directoryPattern = input.directoryPattern,
120            progressBar = input.progress,
121            ticket = input.ticket,
122            fileList = input.list,
123            $container = input.form,    // sometimes a div when inline
124            $modal = $container.parents(".modal-dialog").first();
125
126        if (! $modal.length) {
127            $modal = $container;
128        }
129
130        var uploadUrl = $.service('file', 'upload');
131
132        var restoreExif = function(sourceImageData, newImageData){
133            if (sourceImageData.indexOf('data:image/jpeg;base64,') !== 0){
134                return newImageData;
135            }
136            var sourceImageSegments = MinifyJpeg.slice2Segments(MinifyJpeg.decode64(sourceImageData.replace("data:image/jpeg;base64,", "")));
137            var exifInfo = MinifyJpeg.getExif(sourceImageSegments);
138            var newImageBinArray = MinifyJpeg.insertExif(newImageData, exifInfo);
139            return "data:image/jpeg;base64," + MinifyJpeg.encode64(newImageBinArray);
140        };
141
142        $.each(files, function (k, file) {
143            var reader = new FileReader();
144
145            progressBar.updateSegment(k, 0, file.size);
146            window.lastFile = file;
147
148            $(window).queue('process-upload', function () {
149                reader.onloadend = function (e) {
150                    var xhr, provider, sendData, data, valid = true;
151
152                    $modal.tikiModal(tr("Uploading file..."));
153
154                    xhr = jQuery.ajaxSettings.xhr();
155                    if (xhr.upload) {
156                        xhr.upload.addEventListener('progress', function (e) {
157                            if (e.lengthComputable) {
158                                progressBar.updateSegment(k, e.loaded, e.total);
159                            }
160                        }, false);
161                    }
162                    provider = function () {
163                        return xhr;
164                    };
165
166                    sendData = {
167
168                        type: 'POST',
169                        url: uploadUrl,
170                        xhr: provider,
171                        dataType: 'json',
172                        global: false,     // prevent ajaxError in tiki-jquery.js from closing the dialogs, leading to lost edits
173                        success: function (data) {
174                            fileList.addFile(data.fileId, file, title);
175                        },
176                        error: function (jqXHR, textStatus, errorThrown) {
177                            progressBar.updateSegment(k, 0, 0);
178                            fileList.addError(file, errorThrown);
179                            const tikiFeedback = jqXHR.getResponseHeader('X-Tiki-Feedback');
180                            if (tikiFeedback) {
181                                fileList.list.append(decodeURIComponent(tikiFeedback));
182                            }
183                        },
184                        complete: function (data, textStatus) {
185                            $(window).dequeue('process-upload');
186
187                            if (data.responseJSON) {
188                                ticket = data.responseJSON.ticket;
189                                // for modal
190                                if ($modal !== $container) {
191                                    $('form.file-uploader-result input[name=ticket]').val(ticket);
192                                }
193                                // for both (form when in modal, div when inline)
194                                $container.data('ticket', ticket);
195                            } else {
196                                alert(tr("There was an error: " + textStatus));
197                            }
198                        }
199                    };
200
201                    $modal.tikiModal();
202
203                    if (window.FormData) {
204                        sendData.processData = false;
205                        sendData.contentType = false;
206                        sendData.cache = false;
207
208                        sendData.data = new FormData;
209                        sendData.data.append('galleryId', galleryId);
210                        sendData.data.append('image_max_size_x', image_max_size_x);
211                        sendData.data.append('image_max_size_y', image_max_size_y);
212                        sendData.data.append('ticket', ticket);
213                        sendData.data.append('name', file.name);
214                        sendData.data.append('title', title);
215                        sendData.data.append('directoryPattern', directoryPattern);
216                        if (file.directory) {
217                            sendData.data.append('directory', file.directory);
218                        }
219
220                        var waiting = false;
221
222                        //checking if image is uploaded to call resize function and resizing options are set by tracker
223                        // field creator
224                        if (file.type.substring(0, 6) == 'image/' && (image_max_size_x || image_max_size_y)) {
225                            waiting = true;
226                            var imageData;
227
228                            var picFile = e.target;
229                            imageData = picFile.result;
230
231                            var img = new Image();
232                            var blobImage = null;
233                            img.src = imageData;
234                            img.onload = function () {
235                                var width = parseInt(image_max_size_x);
236                                var height = parseInt(image_max_size_y);
237                                var image_x = parseInt(image_max_size_x);
238                                var image_y = parseInt(image_max_size_y);
239                                var ratio;
240                                if (img.width > image_x || img.height > image_y) {
241
242                                    if (img.width > image_x) {
243                                        width = image_x;
244                                        ratio = image_x / img.width;
245                                        height = Math.round(img.height * ratio);
246                                    }
247
248                                    if (height > image_y) {
249                                        height = image_y;
250                                        ratio = image_y / img.height;
251                                        width = Math.round(img.width * ratio);
252                                    }
253                                } else {
254                                    width = img.width;
255                                    height = img.height;
256                                }
257                                var canvas = $("<canvas/>").get(0);
258                                canvas.width = width;
259                                canvas.height = height;
260                                var context = canvas.getContext('2d');
261                                context.drawImage(img, 0, 0, width, height);
262                                var resizedImage = restoreExif(imageData, canvas.toDataURL('image/jpeg'));
263                                blobImage = dataURItoBlob(resizedImage);
264                                sendData.data.append('data', blobImage, file.name);
265                                $.ajax(sendData);
266                            };
267
268                        } else {
269                            sendData.data.append('data', file);
270                        }
271                    } else {
272                        data = e.target.result;
273                        sendData.data = {
274                            name: file.name,
275                            size: file.size,
276                            type: file.type,
277                            title: title,
278                            data: data.substr(data.indexOf('base64') + 7),
279                            galleryId: galleryId,
280                            image_max_size_x: image_max_size_x,
281                            image_max_size_y: image_max_size_y,
282                            directoryPattern: directoryPattern
283                        };
284                        if (file.directory) {
285                            sendData.data.directory = file.directory;
286                        }
287                    }
288
289                    if (accept) {
290                        valid = file.type.match(new RegExp(".?(" + accept.replace('*', '.*') + ")$", "i"));
291                    }
292
293                    if (valid && !waiting) {
294                        $.ajax(sendData);
295                    } else {
296                        if (!valid) {
297                            sendData.error(null);
298                        }
299                    }
300                };
301                reader.readAsDataURL(file);
302            });
303        });
304        $(window).dequeue('process-upload');
305    };
306
307    $(document).on('submit', 'form.file-uploader', function (e) {
308        e.preventDefault();
309    });
310
311    function getIcon(themeIconset, mimeType, type = "", extension = "") {
312        if (mimeType == undefined) {
313            switch (themeIconset) {
314                case "legacy":
315                    return $('<img height="16" width="16" src="img/icons/mime/default.png">');
316                case "bootstrap_icon_font":
317                    return $('<span class="bi bi-file" style="font-size:200%;"></span>');
318                case "theme_specific_iconset":
319                    return $('<span class="far fa-file" style="font-size:200%;"></span>');
320                default:
321                    return $('<span class="far fa-file" style="font-size:200%;"></span>');
322            }
323        } else {
324            type = type != "" ? `-${type}` : '';
325            switch (themeIconset) {
326                case "legacy":
327                    return $('<img height="16" width="16" title="'+ mimeType +'" alt="'+ mimeType +'" src="img/icons/mime/' + extension + '.png">');
328                case "bootstrap_icon_font":
329                    return $('<span class="bi bi-file' + type + '" style="font-size:200%;"></span>');
330                case "theme_specific_iconset":
331                    return $('<span class="far fa-file' + type + '" style="font-size:200%;"></span>');
332                default:
333                    return $('<span class="far fa-file' + type + '" style="font-size:200%;"></span>');
334            }
335        }
336    }
337
338    function doUpload($form, files) {
339        var progress, list, title = "";
340
341        progress = new ProgressBar({
342            progress: function (current, total) {
343                var percentage = Math.round(current / total * 100);
344
345                $form.find('.progress').removeClass("invisible");
346                $form.find('.progress-bar')
347                    .attr('aria-valuenow', percentage)
348                    .width(percentage + '%');
349                $form.find('.progress-bar .sr-only .count')
350                    .text(percentage);
351            },
352            done: function () {
353                $form.find('.progress').addClass("invisible");
354                $form.find('.progress-bar')
355                    .attr('aria-valuenow', 0)
356                    .width('0%');
357                $form.find('.progress-bar .sr-only .count')
358                    .text('0%');
359                // Clear required title in preparation for next file
360                $('.custom-file-title-input', $form).val('');
361            }
362        });
363
364        list = new FileList({
365            list: $form.parent().find('.file-uploader-result ul')[0]
366        });
367
368        list.clearErrors();
369
370        if ($form.find('.custom-file-title-input').length) {
371            title = $form.find('.custom-file-title-input').val();
372        }
373
374        handleFiles({
375            accept: $form.find(':file').attr('accept'),
376            galleryId: $form.data('gallery-id'),
377            title: title,
378            ticket: $form.data('ticket'),
379            image_max_size_x:$form.data('image_max_size_x'),
380            image_max_size_y:$form.data('image_max_size_y'),
381            directoryPattern: $form.data('directory-pattern'),
382            files: files,
383            progress: progress,
384            list: list,
385            form: $form
386        });
387    }
388
389    function getDirectoryFiles(directory) {
390        let directoryReader = directory.createReader();
391        return new Promise((resolve) => {
392            directoryReader.readEntries(async function (entries) {
393                let files = [];
394                for (let i = 0, l = entries.length; i < l; i++) {
395                    let directoryFiles = await readDirectoryEntry(entries[i], directory);
396                    files = files.concat(directoryFiles);
397                };
398                resolve(files);
399            });
400        });
401    }
402
403    function readDirectoryEntry(entry, directory) {
404        if (entry.isDirectory) {
405            return getDirectoryFiles(entry);
406        } else {
407            return new Promise((resolve) => {
408                entry.file((file) => {
409                    file.directory = directory ? directory.fullPath : null;
410                    resolve([file]);
411                });
412            });
413        }
414    }
415
416    function validateTitleProvided(form) {
417        if ($('.custom-file-title', form).is(':visible')) {
418            if (!$('.custom-file-title-input', form).val()) {
419                $('.custom-file-title .feedback-required-title', form).show();
420                $('.custom-file-label', form).text('Choose file');
421                form.trigger('reset');
422                return false;
423            } else {
424                $('.custom-file-title .feedback-required-title', form).hide();
425                return true;
426            }
427        }
428        return true;
429    }
430
431    function validateOneAtTime(form, files) {
432        if ($('.custom-file-title', form).is(':visible')) {
433            if (files.length > 1) {
434                $('.custom-file-title .feedback-one-at-time', form).show();
435                $('.custom-file-label', form).text('Choose file');
436                form.trigger('reset');
437                return false;
438            } else {
439                $('.custom-file-title .feedback-one-at-time', form).hide();
440                return true;
441            }
442        }
443        return true;
444    }
445
446    $(document).on('change', '.file-uploader input[type=file]', function () {
447
448        var $clone, $form = $(this).closest("form"), progress, list;
449        if (this.files) {
450            if (!validateTitleProvided($form)) {
451                return false;
452            }
453            if (!validateOneAtTime($form, this.files)) {
454                return false;
455            }
456
457            let $inlineDiv = $(this).parents(".file-uploader.inline");
458
459            if ($inlineDiv.length) {
460                doUpload($inlineDiv, this.files);
461            } else {
462                doUpload($form, this.files);
463            }
464
465            $(this).val('');
466            $clone = $(this).clone(true);
467            $(this).replaceWith($clone);
468        }
469    });
470
471    if (window.FileReader) {
472        $(function () {
473            $('.drop-message').show();
474        });
475        $(document).on('dragenter', '.file-uploader', function (e) {
476            e.preventDefault();
477            e.stopPropagation();
478            $(this).addClass("active");
479            return false;
480        });
481        $(document).on('dragexit dragleave', '.file-uploader', function (e) {
482            e.preventDefault();
483            e.stopPropagation();
484            $(this).removeClass("active");
485            return false;
486        });
487        $(document).on('dragover', '.file-uploader', function (e) {
488            e.preventDefault();
489            e.stopPropagation();
490            return false;
491        });
492        $(document).on('drop', '.file-uploader', async function (e) {
493            var $form = $(this);
494
495            if (!validateTitleProvided($form)) {
496                return false;
497            }
498
499            e.preventDefault();
500            e.stopPropagation();
501            $(this).removeClass("active");
502
503            var dataTransfer = e.dataTransfer;
504            if (! dataTransfer) {
505                dataTransfer = e.originalEvent.dataTransfer;
506            }
507
508            if (dataTransfer && dataTransfer.items) {
509                let files = [];
510                let items = [];
511                for (let item of dataTransfer.items) {
512                    items.push(item.webkitGetAsEntry());
513                }
514                for (let item of items) {
515                    if (item) {
516                        let itemFiles = await readDirectoryEntry(item, null);
517                        files = files.concat(itemFiles);
518                    }
519                }
520                if (!validateOneAtTime($form, files)) {
521                    return false;
522                }
523                doUpload($form, files);
524            }
525            return false;
526        });
527    }
528
529    $(document).on('click', '.file-browser .gallery-list .pagination a', function (e) {
530        e.preventDefault();
531        $(this).closest('.modal').animate({ scrollTop: 0 }, 'slow');
532        $(this).closest('.gallery-list')
533            .tikiModal(tr('Loading...'))
534            .load($(this).attr('href'), function () {
535                $(this).tikiModal('');
536            });
537    });
538
539    $(document).on('submit', '.file-browser form.no-ajax[method="get"]', function (e) {
540        e.preventDefault();
541        const $form = $(this);
542        const $fileBrowser = $form.closest('.file-browser');
543        const $galleryList = $fileBrowser.find('.gallery-list');
544        const url = $form.attr('action');
545        const data = $form.serialize();
546
547        $galleryList.tikiModal(tr('Loading...'));
548
549        $.get(url, data)
550            .done(function (response) {
551                $galleryList.html(response);
552                $galleryList.tikiModal('');
553            })
554            .fail(function () {
555                $galleryList.html('<div class="alert alert-danger">' + tr('Error loading results.') + '</div>');
556                $galleryList.tikiModal('');
557            });
558    });
559
560    $(document).on('click', '.file-browser .submit .upload-files', function (e) {
561        var $list = $(this).closest('.file-browser').find('.selection ul'),
562            handler = $.clickModal({
563                success: function (data) {
564                    $.each(data.files, function (k, file) {
565                        $('<li>')
566                            .append($('<a href="#">')
567                                .data('object', file.fileId)
568                                .data('type', 'file')
569                                .text(file.label))
570                            .append($('<input type="hidden" name="file[]">')
571                                .attr('value', file.fileId))
572                            .appendTo($list);
573
574                    });
575                    $.closeModal();
576                }
577            });
578
579        handler.apply(this, arguments);
580    });
581
582    // File selector component
583    $(document).on('click', '.file-selector a', function () {
584        if (! $(this).data('initial-href')) {
585            $(this).data('initial-href', $(this).attr('href'));
586        }
587
588        // Before the dialog handler triggers, replace the href with one including current files
589        $(this).attr('href', $(this).data('initial-href') + '&file=' + $(this).parent().children('input').val());
590    });
591    $(document).on('click', '.file-selector a', $.clickModal({
592        size: 'modal-lg',
593        success: function (data) {
594            var files = [];
595            $.each(data.files, function (k, f) {
596                files.push(f.fileId);
597            });
598            $(this).parent().children('input').val(files.join(','));
599            $(this).text($(this).text().replace(/\d+/, files.length));
600            $.closeModal();
601        }
602    }));
603
604    $(document).on('change', '#fgal_type', function () {
605        $(this).closest('form').find('.fgal_type_dependent').hide();
606        $(this).closest('form').find('.fgal_type_dependent.' + $(this).val() + '_childcontainer').show();
607        $('#direct_adapter').trigger('change');
608    });
609    $(document).on('change', '#direct_adapter', function () {
610        $(this).closest('form').find('.direct_adapter_dependent').hide();
611        if ($(this).is(':visible')) {
612            $(this).closest('form').find('.direct_adapter_dependent.' + $(this).val() + '_childcontainer').show();
613        }
614    });
615
616    $(document).ready(function() {
617        $('input[type="file"]').on('change', function() {
618            updateFileName(this);
619        });
620    });
621
622    $(document).on('click', '.file-browser .gallery-list .pagination a', function (e) {
623        e.preventDefault();
624        $('#select-all-files').prop('checked', false);
625        $(this).closest('.modal').animate({ scrollTop: 0 }, 'slow');
626        $(this).closest('.gallery-list')
627            .tikiModal(tr('Loading...'))
628            .load($(this).attr('href'), function () {
629                $(this).tikiModal('');
630            });
631    });
632
633    $(document).on('click', '.file-title-toggle', function (e) {
634        e.preventDefault();
635        const targetId = $(this).data('checkbox-id');
636        const checkbox = document.getElementById(targetId);
637        if (checkbox) {
638            checkbox.checked = !checkbox.checked;
639        }
640    });
641
642})(jQuery);
643
644function updateFileName(inputFile) {
645    const fileNameField = inputFile.previousElementSibling;
646    if (! fileNameField) { return; }
647    if (inputFile.files.length > 0) {
648        fileNameField.value = inputFile.files[0].name;
649    } else {
650        fileNameField.value = fileNameField.getAttribute('placeholder');
651    }
652}
653
654function dataURItoBlob(dataURI) {
655
656
657    // convert base64/URLEncoded data component to raw binary data held in a string
658    var byteString;
659    if (dataURI.split(',')[0].indexOf('base64') >= 0) {
660        byteString = atob(dataURI.split(',')[1]);
661    } else {
662        byteString = unescape(dataURI.split(',')[1]);
663    }
664
665    // write the bytes of the string to a typed array
666    var ia = new Uint8Array(byteString.length);
667    for (var i = 0; i < byteString.length; i++) {
668        ia[i] = byteString.charCodeAt(i);
669    }
670
671    return new Blob([ia],{ type:'image/jpeg' });
672}
673
674/* To minify a jpeg image without loosing EXIF.
675 * TESTED(24/01/2013): FireFox, GoogleChrome, IE10, Opera
676 * Copyright (c) 2013 hMatoba
677 * Released under the MIT license : https://github.com/hMatoba/MinifyJpegAsync/blob/master/LICENSE.txt
678 *
679 * To minify jpeg image:
680 *     minified = MinifyJpeg.minify(image, length);
681 *     xhr.send(minified.buffer);
682 *     enc = "data:image/jpeg;base64," + MinifyJpeg.encode64(minified);
683 *     html = '<img src="' + enc + '">';
684 * MinifyJpeg.minify() - return Uint8Array
685 * image - image base64encoded, it can be obtained "FileReader().readAsDataURL(f)"
686 * length - the long side length of the rectangle
687 * MinifyJpeg.encode64() - convert array to base64encoded string
688 */
689var MinifyJpeg = (function () {
690
691    var that = {};
692
693    that.KEY_STR = "ABCDEFGHIJKLMNOP" +
694        "QRSTUVWXYZabcdef" +
695        "ghijklmnopqrstuv" +
696        "wxyz0123456789+/" +
697        "=";
698
699    that.SOF = [192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207];
700
701    that.minify = function (image, new_size) {
702        var newImage, rawImage;
703
704        if (image instanceof ArrayBuffer) {
705            if (image[0] == 255 && image[1] == 216) {
706                rawImage = [];
707                for (var i = 0; i < image.byteLength; i++) {
708                    rawImage[i] = image[i];
709                }
710            }
711            else {
712                throw "MinifyJpeg.minify got a not JPEG data";
713            }
714        }
715        else {
716            if (typeof(image) === "string") {
717                if (!image.match("data:image/jpeg;base64,")) {
718                    throw "MinifyJpeg.minify got a not JPEG data";
719                }
720                else {
721                    rawImage = that.decode64(image.replace("data:image/jpeg;base64,", ""));
722                }
723            }
724            else {
725                throw "First argument must be 'DataURL string' or ArrayBuffer.";
726            }
727        }
728
729        var segments = that.slice2Segments(rawImage);
730        var NEW_SIZE = parseInt(new_size);
731        var size = that.imageSizeFromSegments(segments);
732        var chouhen = (size[0] >= size[1]) ? size[0] : size[1];
733        if (chouhen < NEW_SIZE) {
734            return new Uint8Array(rawImage);
735        }
736
737        var exif = that.getExif(segments);
738        var resized = that.resizeImage(rawImage, segments, NEW_SIZE);
739
740        if (exif.length) {
741            newImage = that.insertExif(resized, exif);
742        }
743        else {
744            newImage = new Uint8Array(that.decode64(resized.replace("data:image/jpeg;base64,", "")));
745        }
746
747        return newImage;
748    };
749
750    that.getImageSize = function (imageArray) {
751        var segments = that.slice2Segments(imageArray);
752        return that.imageSizeFromSegments(segments);
753    };
754
755    that.slice2Segments = function (rawImageArray) {
756        var head = 0,
757            segments = [];
758
759        while (1) {
760            if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 218) {
761                break;
762            }
763            if (rawImageArray[head] == 255 & rawImageArray[head + 1] == 216) {
764                head += 2;
765            }
766            else {
767                var length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3],
768                    endPoint = head + length + 2,
769                    seg = rawImageArray.slice(head, endPoint);
770                segments.push(seg);
771                head = endPoint;
772            }
773            if (head > rawImageArray.length) {
774                break;
775            }
776        }
777
778        return segments;
779    };
780
781    that.imageSizeFromSegments = function (segments) {
782        for (var x = 0; x < segments.length; x++) {
783            var seg = segments[x];
784            if (that.SOF.indexOf(seg[1]) >= 0) {
785                var height = seg[5] * 256 + seg[6],
786                    width = seg[7] * 256 + seg[8];
787                break;
788            }
789        }
790        return [width, height];
791    };
792
793    that.encode64 = function (input) {
794        var output = "",
795            chr1, chr2, chr3 = "",
796            enc1, enc2, enc3, enc4 = "",
797            i = 0;
798
799        do {
800            chr1 = input[i++];
801            chr2 = input[i++];
802            chr3 = input[i++];
803
804            enc1 = chr1 >> 2;
805            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
806            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
807            enc4 = chr3 & 63;
808
809            if (isNaN(chr2)) {
810                enc3 = enc4 = 64;
811            } else {
812                if (isNaN(chr3)) {
813                    enc4 = 64;
814                }
815            }
816
817            output += that.KEY_STR.charAt(enc1) +
818                that.KEY_STR.charAt(enc2) +
819                that.KEY_STR.charAt(enc3) +
820                that.KEY_STR.charAt(enc4);
821            chr1 = chr2 = chr3 = "";
822            enc1 = enc2 = enc3 = enc4 = "";
823        } while (i < input.length);
824        return output;
825    };
826
827    that.decode64 = function (input) {
828        var chr1, chr2, chr3 = "",
829            enc1, enc2, enc3, enc4 = "",
830            i = 0,
831            buf = [];
832
833        // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
834        var base64test = /[^A-Za-z0-9\+\/\=]/g;
835        if (base64test.exec(input)) {
836            alert("There were invalid base64 characters in the input text.\n" +
837                "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
838                "Expect errors in decoding.");
839        }
840        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
841
842        do {
843            enc1 = that.KEY_STR.indexOf(input.charAt(i++));
844            enc2 = that.KEY_STR.indexOf(input.charAt(i++));
845            enc3 = that.KEY_STR.indexOf(input.charAt(i++));
846            enc4 = that.KEY_STR.indexOf(input.charAt(i++));
847
848            chr1 = (enc1 << 2) | (enc2 >> 4);
849            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
850            chr3 = ((enc3 & 3) << 6) | enc4;
851
852            buf.push(chr1);
853
854            if (enc3 != 64) {
855                buf.push(chr2);
856            }
857            if (enc4 != 64) {
858                buf.push(chr3);
859            }
860
861            chr1 = chr2 = chr3 = "";
862            enc1 = enc2 = enc3 = enc4 = "";
863
864        } while (i < input.length);
865
866        return buf;
867    };
868
869    that.resizeImage = function (rawImage, segments, NEW_SIZE) {
870        var jpe, ctx, srcImg;
871        var size = that.imageSizeFromSegments(segments),
872            width = size[0],
873            height = size[1],
874            chouhen = (width >= height) ? width : height,
875            newSize = NEW_SIZE,
876            resizing = 1,
877            scale = parseFloat(newSize) / chouhen,
878            newWidth = parseInt(parseFloat(newSize) / chouhen * width),
879            newHeight = parseInt(parseFloat(newSize) / chouhen * height);
880
881        if (resizing == 1) // bilinear
882        {
883            var canvas = document.createElement('canvas');
884            canvas.width = width;
885            canvas.height = height;
886
887            jpe = new JpegImage();
888            ctx = canvas.getContext("2d");
889            srcImg = ctx.getImageData(0, 0, width, height);
890            jpe.parse(new Uint8Array(rawImage));
891            jpe.copyToImageData(srcImg);
892
893            var newCanvas = document.createElement('canvas');
894            newCanvas.width = newWidth;
895            newCanvas.height = newHeight;
896            var newCtx = newCanvas.getContext("2d");
897            var destImg = newCtx.createImageData(newWidth, newHeight);
898            that.bilinear(srcImg, destImg, scale);
899
900            newCtx.putImageData(destImg, 0, 0);
901            var resizedImage = newCanvas.toDataURL("image/jpeg");
902        }
903        else // nearest neighbor?
904        {
905            canvas = document.createElement('canvas');
906            canvas.width = newWidth;
907            canvas.height = newHeight;
908
909            jpe = new JpegImage();
910            ctx = canvas.getContext("2d");
911            d = ctx.getImageData(0, 0, newWidth, newHeight);
912            jpe.parse(new Uint8Array(rawImage));
913            jpe.copyToImageData(d);
914            ctx.putImageData(d, 0, 0);
915
916            resizedImage = canvas.toDataURL("image/jpeg");
917        }
918
919        return resizedImage;
920    };
921
922    that.getExif = function (segments) {
923        var seg;
924        for (var x = 0; x < segments.length; x++) {
925            seg = segments[x];
926            if (seg[0] == 255 & seg[1] == 225) //(ff e1)
927            {
928                return seg;
929            }
930        }
931        return [];
932    };
933
934    that.insertExif = function (imageStr, exifArray) {
935        var buf = that.decode64(imageStr.replace("data:image/jpeg;base64,", "")),
936            separatePoint = buf.indexOf(255, 3),
937            mae = buf.slice(0, separatePoint),
938            ato = buf.slice(separatePoint),
939            array = mae.concat(exifArray, ato);
940
941        aBuffer = new Uint8Array(array);
942
943        return aBuffer;
944    };
945
946    // compute vector index from matrix one
947    that.ivect = function (ix, iy, w) {
948        // byte array, r,g,b,a
949        return ((ix + w * iy) * 4);
950    };
951
952    that.bilinear = function (srcImg, destImg, scale) {
953        // c.f.: wikipedia english article on bilinear interpolation
954        //log.debug("in bilinear");
955        // taking the unit square
956        function inner(f00, f10, f01, f11, x, y)
957        {
958            var un_x = 1.0 - x;
959            var un_y = 1.0 - y;
960            return (f00 * un_x * un_y + f10 * x * un_y + f01 * un_x * y + f11 * x * y);
961        }
962
963        var srcWidth = srcImg.width;
964        var srcHeight = srcImg.height;
965        var srcData = srcImg.data;
966        var dstData = destImg.data;
967        var i, j;
968        var iyv, iy0, iy1, ixv, ix0, ix1;
969        var idxD, idxS00, idxS10, idxS01, idxS11;
970        var dx, dy;
971        for (i = 0; i < destImg.height; ++i) {
972            iyv = (i + 0.5) / scale - 0.5;
973            iy0 = Math.floor(iyv);
974            iy1 = (Math.ceil(iyv) > (srcHeight - 1) ? (srcHeight - 1) : Math.ceil(iyv));
975            for (j = 0; j < destImg.width; ++j) {
976                ixv = (j + 0.5) / scale - 0.5;
977                ix0 = Math.floor(ixv);
978                ix1 = (Math.ceil(ixv) > (srcWidth - 1) ? (srcWidth - 1) : Math.ceil(ixv));
979                idxD = that.ivect(j, i, destImg.width);
980                idxS00 = that.ivect(ix0, iy0, srcWidth);
981                idxS10 = that.ivect(ix1, iy0, srcWidth);
982                idxS01 = that.ivect(ix0, iy1, srcWidth);
983                idxS11 = that.ivect(ix1, iy1, srcWidth);
984                // log.debug(sprintf("bilinear: idx: D: %d, S00: %d, S10: %d, S01: %d, S11: %d", idxD, idxS00, idxS10,
985                // idxS01, idxS11));
986                dx = ixv - ix0;
987                dy = iyv - iy0;
988
989                //r
990                dstData[idxD] = inner(srcData[idxS00], srcData[idxS10],
991                    srcData[idxS01], srcData[idxS11], dx, dy
992                );
993
994                //g
995                dstData[idxD + 1] = inner(srcData[idxS00 + 1], srcData[idxS10 + 1],
996                    srcData[idxS01 + 1], srcData[idxS11 + 1], dx, dy
997                );
998
999                //b
1000                dstData[idxD + 2] = inner(srcData[idxS00 + 2], srcData[idxS10 + 2],
1001                    srcData[idxS01 + 2], srcData[idxS11 + 2], dx, dy
1002                );
1003
1004                //a
1005                dstData[idxD + 3] = inner(srcData[idxS00 + 3], srcData[idxS10 + 3],
1006                    srcData[idxS01 + 3], srcData[idxS11 + 3], dx, dy
1007                );
1008            }
1009        }
1010    };
1011    return that;
1012})();
1013
1014function processFgalSyntax(fileInfo, theSyntax) {
1015    if (Array.isArray(fileInfo)) {
1016        let syntax = "";
1017        for (var i = 0; i < fileInfo.length; i++) {
1018            if (i > 0) {
1019                syntax += "\n";
1020            }
1021            syntax += fgalSyntax(fileInfo[i], theSyntax);
1022        }
1023        return syntax;
1024    } else {
1025        return fgalSyntax(fileInfo, theSyntax);
1026    }
1027}
1028
1029function fgalSyntax(fileInfo, theSyntax) {
1030    var key, part, syntax = "";
1031    if (typeof fileInfo === "string") {
1032        fileInfo = JSON.parse(fileInfo);
1033    }
1034    syntax = syntax ? decodeURIComponent(syntax[1]) : (theSyntax || fileInfo.syntax || fileInfo.wiki_syntax);
1035    for (key in fileInfo) {
1036        if (fileInfo.hasOwnProperty(key)) {
1037            part = "{" + key + "}";
1038            if (syntax.indexOf(part) > -1) {
1039                syntax = syntax.replace(part, fileInfo[key]);
1040            }
1041        }
1042    }
1043    return syntax;
1044}

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.