/**
 * User: Jinqn
 * Date: 14-04-08
 * Time: 下午16:34
 * 上传图片对话框逻辑代码,包括tab: 远程图片/上传图片/在线图片/搜索图片
 */

// 立即执行函数，用于创建一个独立的作用域，避免变量污染全局环境
(function () {

    // 定义两个变量，用于存储上传文件相关对象和在线文件相关对象，初始值为 undefined，后续会根据情况进行赋值
    var uploadFile,
        onlineFile;

    // 当页面加载完成时触发的事件处理函数，用于执行一些初始化操作
    window.onload = function () {
        // 调用 initTabs 函数，用于初始化 tab 标签相关的交互逻辑等功能
        initTabs();
        // 调用 initButtons 函数，用于初始化按钮相关的事件处理等功能
        initButtons();
    };

    /* 初始化tab标签 */
    function initTabs() {
        // 通过自定义函数 $G 获取 id 为 'tabhead' 的元素，并获取其所有子元素（可能是各个 tab 标签元素）
        var tabs = $G('tabhead').children;
        // 循环遍历每个 tab 标签元素
        for (var i = 0; i < tabs.length; i++) {
            // 使用 domUtils 对象的 on 方法（可能是自定义的事件绑定函数）为每个 tab 标签元素绑定点击事件处理函数
            domUtils.on(tabs[i], "click", function (e) {
                // 获取触发点击事件的实际目标元素，兼容不同浏览器获取方式（e.target 适用于标准浏览器，e.srcElement 适用于IE浏览器）
                var target = e.target || e.srcElement;
                // 调用 setTabFocus 函数，传入目标元素的 data-content-id 属性值（可能用于标识对应的内容区域等），设置当前选中的 tab 标签焦点
                setTabFocus(target.getAttribute('data-content-id'));
            });
        }

        // 初始设置 'upload' 对应的 tab 标签为焦点状态（默认选中），调用 setTabFocus 函数并传入 'upload'
        setTabFocus('upload');
    }

    /* 初始化tabbody */
    function setTabFocus(id) {
        // 如果传入的 id 参数为空值，则直接返回，不执行后续操作
        if (!id) return;
        // 定义循环变量 i 和用于存储 tab 标签对应内容区域 id 的变量 bodyId，同时获取所有 tab 标签元素
        var i, bodyId, tabs = $G('tabhead').children;
        // 循环遍历每个 tab 标签元素
        for (i = 0; i < tabs.length; i++) {
            // 获取当前 tab 标签元素的 data-content-id 属性值，赋值给 bodyId，该值可能对应着相关的内容区域元素的 id
            bodyId = tabs[i].getAttribute('data-content-id')
            // 如果当前 tab 标签元素的 data-content-id 属性值与传入的 id 参数相等，说明该 tab 标签被选中
            if (bodyId == id) {
                // 使用 domUtils 对象的 addClass 方法（可能是自定义的添加类名函数）给当前 tab 标签元素添加 'focus' 类名，用于设置样式等体现焦点状态
                domUtils.addClass(tabs[i], 'focus');
                // 使用 domUtils 对象的 addClass 方法给对应的内容区域元素（通过 $G 获取，传入 bodyId）也添加 'focus' 类名，同样用于体现焦点相关样式等
                domUtils.addClass($G(bodyId), 'focus');
            } else {
                // 如果当前 tab 标签元素的 data-content-id 属性值与传入的 id 参数不相等，使用 domUtils 对象的 removeClasses 方法（可能是自定义的移除类名函数）从当前 tab 标签元素移除 'focus' 类名
                domUtils.removeClasses(tabs[i], 'focus');
                // 使用 domUtils 对象的 removeClasses 方法从对应的内容区域元素移除 'focus' 类名
                domUtils.removeClasses($G(bodyId), 'focus');
            }
        }
        // 根据传入的 id 参数值进行不同的操作
        switch (id) {
            // 如果 id 为 'upload'，表示当前选中的是上传文件相关的 tab 标签
            case 'upload':
                // 如果 uploadFile 变量还未赋值（即 undefined），则创建一个 UploadFile 类的实例（传入 'queueList' 作为参数，可能用于标识相关队列等信息）并赋值给 uploadFile 变量
                uploadFile = uploadFile || new UploadFile('queueList');
                break;
            // 如果 id 为 'online'，表示当前选中的是在线文件相关的 tab 标签
            case 'online':
                // 如果 onlineFile 变量还未赋值（即 undefined），则创建一个 OnlineFile 类的实例（传入 'fileList' 作为参数，可能用于标识相关文件列表等信息）并赋值给 onlineFile 变量
                onlineFile = onlineFile || new OnlineFile('fileList');
                break;
        }
    }

    /* 初始化onok事件 */
    function initButtons() {

        // 给 dialog 对象的 onok 属性（可能是对话框确认按钮点击时触发的事件处理函数）赋值一个函数
        dialog.onok = function () {
            // 创建一个空数组 list，用于存储要插入的文件相关信息，后续会根据不同情况填充内容
            var list = [], id, tabs = $G('tabhead').children;
            // 循环遍历所有 tab 标签元素，查找当前处于焦点状态（被选中）的 tab 标签
            for (var i = 0; i < tabs.length; i++) {
                if (domUtils.hasClass(tabs[i], 'focus')) {
                    // 获取当前焦点 tab 标签的 data-content-id 属性值，赋值给 id，用于判断当前处于哪个功能模块（上传文件或在线文件等）
                    id = tabs[i].getAttribute('data-content-id');
                    break;
                }
            }

            // 根据获取到的 id 值进行不同的操作
            switch (id) {
                // 如果 id 为 'upload'，表示当前处于上传文件相关的功能模块
                case 'upload':
                    // 调用 uploadFile 对象的 getInsertList 方法（可能用于获取要插入的文件列表信息），将返回结果赋值给 list 数组
                    list = uploadFile.getInsertList();
                    // 调用 uploadFile 对象的 getQueueCount 方法（可能用于获取未上传文件的数量），获取未上传文件的数量并赋值给 count 变量
                    var count = uploadFile.getQueueCount();
                    // 如果还有未上传的文件（count 不为0）
                    if (count) {
                        // 使用 jQuery 选择器（$('.info', '#queueList')，可能是获取 id 为 'queueList' 元素内部的类名为 'info' 的元素）找到对应的元素，并设置其 HTML 内容
                        // 内容中包含一个提示信息，使用字符串替换将 '还有2个未上传文件' 中的数字替换为实际的未上传文件数量（count），颜色设置为红色，用于提示用户还有文件未上传
                        $('.info', '#queueList').html('<span style="color:red;">' + '还有2个未上传文件'.replace(/[\d]/, count) + '</span>');
                        // 返回 false，可能用于阻止对话框继续执行后续的默认操作（比如关闭等），提示用户先处理未上传文件的情况
                        return false;
                    }
                    break;
                // 如果 id 为 'online'，表示当前处于在线文件相关的功能模块
                case 'online':
                    // 调用 onlineFile 对象的 getInsertList 方法（可能用于获取要插入的在线文件列表信息），将返回结果赋值给 list 数组
                    list = onlineFile.getInsertList();
                    break;
            }

            // 调用 editor 对象的 execCommand 方法（可能是执行编辑器相关命令的函数），传入 'insertfile' 命令以及 list 数组（包含要插入的文件信息），执行插入文件相关的操作
            editor.execCommand('insertfile', list);
        };
    }


    /* 上传附件 */
// 定义一个名为UploadFile的构造函数，用于创建与上传文件相关的对象实例，接收一个参数target，用于指定相关的DOM元素或元素的id标识等
function UploadFile(target) {
    // 判断传入的target参数是否为字符串类型，如果是，则通过jQuery选择器根据该字符串（当作id）获取对应的DOM元素，否则直接将传入的参数当作jQuery对象（可能已经是选择好的DOM元素）进行赋值，最终将获取到的元素或对象赋值给this.$wrap属性，用于后续操作中代表与上传文件相关的包裹元素
    this.$wrap = target.constructor == String? $('#' + target) : $(target);
    // 调用init方法，用于进行一些初始化操作，比如初始化文件列表、容器等相关设置
    this.init();
}

// 为UploadFile构造函数的原型对象添加属性和方法，这样通过该构造函数创建的所有实例对象都可以共享这些属性和方法
UploadFile.prototype = {
    // 定义init方法，用于进行一系列的初始化工作，是整个上传文件功能初始化的入口函数
    init: function () {
        // 创建一个空数组，用于存储上传文件的相关信息列表（比如文件名、文件大小等信息，后续会根据实际情况填充内容），并将其赋值给this.fileList属性，方便在实例对象中记录和操作文件相关数据
        this.fileList = [];
        // 调用initContainer方法，用于初始化与上传文件相关的容器元素，比如文件列表展示区域等
        this.initContainer();
        // 调用initUploader方法，用于初始化文件上传相关的功能配置，例如创建WebUploader实例、设置各种上传相关的参数等
        this.initUploader();
    },
    // 定义initContainer方法，用于初始化与上传文件相关的容器元素，找到对应的DOM元素并赋值给相应的属性，方便后续操作
    initContainer: function () {
        // 通过jQuery的find方法，在之前初始化的this.$wrap（代表与上传文件相关的包裹元素）中查找类名为'filelist'的元素，并将找到的元素赋值给this.$queue属性，可能用于后续展示文件列表等操作
        this.$queue = this.$wrap.find('.filelist');
    },
    /* 初始化容器 */
    initUploader: function () {
        // 将当前实例对象（this）赋值给变量_this，用于在后续一些闭包环境中能正确访问到当前实例对象的属性和方法，避免this指向问题导致的错误
        var _this = this,
            $ = jQuery,    // just in case. Make sure it's not an other libaray.
            // 获取当前实例对象的$wrap属性（代表与上传文件相关的包裹元素），赋值给变量$wrap，方便后续使用
            $wrap = _this.$wrap,
            // 图片容器，通过在$wrap元素内查找类名为'filelist'的元素，获取到用于展示图片等文件的容器元素，可能用于展示上传文件的缩略图等信息，赋值给变量$queue
            $queue = $wrap.find('.filelist'),
            // 状态栏，包括进度和控制按钮，通过在$wrap元素内查找类名为'statusBar'的元素，获取到用于展示文件上传状态（如进度条、相关控制按钮所在的区域）的元素，赋值给变量$statusBar
            $statusBar = $wrap.find('.statusBar'),
            // 文件总体选择信息。通过在$statusBar元素内查找类名为'info'的元素，获取到用于展示文件总体选择情况（如已选文件数量、文件总大小等信息）的元素，赋值给变量$info
            $info = $statusBar.find('.info'),
            // 上传按钮，通过在$wrap元素内查找类名为'uploadBtn'的元素，获取到用于触发文件上传操作的按钮元素，赋值给变量$upload
            $upload = $wrap.find('.uploadBtn'),
            // 上传按钮，通过在$wrap元素内查找类名为'filePickerBtn'的元素，获取到可能用于选择文件的按钮元素（比如打开文件选择对话框的按钮），赋值给变量$filePickerBtn
            $filePickerBtn = $wrap.find('.filePickerBtn'),
            // 上传按钮，通过在$wrap元素内查找类名为'filePickerBlock'的元素，获取到与文件选择相关的某个块状元素（具体作用需根据上下文确定，可能是包含文件选择按钮等相关元素的一个区域），赋值给变量$filePickerBlock
            $filePickerBlock = $wrap.find('.filePickerBlock'),
            // 没选择文件之前的内容。通过在$wrap元素内查找类名为'placeholder'的元素，获取到在还未选择文件时显示的占位元素（比如提示用户选择文件的提示文字所在元素等），赋值给变量$placeHolder
            $placeHolder = $wrap.find('.placeholder'),
            // 总体进度条，通过在$statusBar元素内查找类名为'progress'的元素获取到进度条元素，并调用hide方法将其初始设置为隐藏状态（可能在文件上传开始后再显示），赋值给变量$progress
            $progress = $statusBar.find('.progress').hide(),
            // 添加的文件数量，初始化为0，用于记录已经添加到上传队列中的文件数量，后续会根据实际添加文件的情况进行累加
            fileCount = 0,
            // 添加的文件总大小，初始化为0，用于记录已经添加到上传队列中的所有文件的总大小，单位可能是字节等，后续会根据实际添加文件的大小情况进行累加
            fileSize = 0,
            // 优化retina, 在retina下这个值是2，获取设备的像素比（window.devicePixelRatio），如果不存在则默认为1，用于根据设备的像素情况对一些元素（如缩略图等）的尺寸进行适配，比如在高清屏幕（retina屏幕）上让元素显示更清晰
            ratio = window.devicePixelRatio || 1,
            // 缩略图大小，根据之前获取的像素比（ratio）计算缩略图的宽度和高度，初始化为113乘以像素比，使缩略图在不同像素密度的屏幕上能有合适的尺寸显示
            thumbnailWidth = 113 * ratio,
            thumbnailHeight = 113 * ratio,
            // 可能有pedding, ready, uploading, confirm, done. 定义一个变量state用于记录文件上传的状态，初始为空字符串，后续会根据文件上传的不同阶段（如等待、准备好、正在上传、确认、完成等）设置相应的值来表示当前状态
            state = '',
            // 所有文件的进度信息，key为file id，创建一个空对象percentages，用于存储每个文件（以文件的id作为键）对应的上传进度信息（比如已上传百分比等），方便在上传过程中更新和查询各个文件的进度情况
            percentages = {},
            // 检测浏览器是否支持CSS过渡效果（transition），通过创建一个临时的<p>元素，检查其样式对象中是否存在'transition'或各浏览器前缀版本的'transition'属性来判断，将判断结果（布尔值）赋值给变量supportTransition，用于后续可能涉及到的动画效果等相关操作判断浏览器是否支持
            supportTransition = (function () {
                var s = document.createElement('p').style,
                    r = 'transition' in s ||
                        'WebkitTransition' in s ||
                        'MozTransition' in s ||
                        'msTransition' in s ||
                        'OTransition' in s;
                s = null;
                return r;
            })(),
            // WebUploader实例，用于后续创建和配置实际的文件上传功能，初始化为未赋值状态，后续会进行实例化操作并配置相关参数
            uploader,
            // 获取文件上传的目标URL地址，通过调用editor对象的getActionUrl方法，并传入editor对象的getOpt方法获取的'fileActionName'配置项作为参数，用于指定文件要上传到的服务器端地址，赋值给变量actionUrl
            actionUrl = editor.getActionUrl(editor.getOpt('fileActionName')),
            // 获取允许上传的文件最大大小限制，通过调用editor对象的getOpt方法获取'fileMaxSize'配置项的值，用于在文件选择等阶段判断文件大小是否超出限制，赋值给变量fileMaxSize
            fileMaxSize = editor.getOpt('fileMaxSize'),
            // 获取允许上传的文件类型扩展名，先通过调用editor对象的getOpt方法获取'fileAllowFiles'配置项（可能是一个数组），将其转换为字符串后进行一些格式处理（替换点号为逗号，去除开头可能出现的逗号），得到允许上传的文件类型扩展名字符串，赋值给变量acceptExtensions
            acceptExtensions = (editor.getOpt('fileAllowFiles') || []).join('').replace(/\./g, ',').replace(/^[,]/, '');;

        // 判断WebUploader.Uploader是否支持当前浏览器环境，如果不支持
        if (!WebUploader.Uploader.support()) {
            // 在id为'filePickerReady'的元素后面插入一个新创建的<div>元素，其HTML内容为lang.errorNotSupport（可能是定义好的提示不支持的错误信息），然后调用hide方法将其隐藏起来，同时直接返回，不再执行后续的初始化操作，因为不支持则无法进行文件上传功能的初始化了
            $('#filePickerReady').after($('<div>').html(lang.errorNotSupport)).hide();
            return;
        } else if (!editor.getOpt('fileActionName')) {
            // 如果editor对象中没有配置'fileActionName'（可能是必须配置的文件上传相关的关键参数），同样在id为'filePickerReady'的元素后面插入一个新创建的<div>元素，其HTML内容为lang.errorLoadConfig（可能是定义好的提示加载配置错误的信息），然后调用hide方法将其隐藏起来，并且直接返回，不再继续后续的初始化流程，因为缺少关键配置无法进行正常的文件上传初始化操作
            $('#filePickerReady').after($('<div>').html(lang.errorLoadConfig)).hide();
            return;
        }

            // 创建一个WebUploader实例，用于实现文件上传功能，并将其赋值给uploader变量以及当前实例对象（_this）的uploader属性，方便后续通过不同方式访问该实例
// 同时传入一个配置对象，用于配置WebUploader的各项参数
uploader = _this.uploader = WebUploader.create({
    // 设置文件选择区域相关的配置
    pick: {
        // 指定文件选择区域对应的DOM元素的id为'filePickerReady'，这意味着该区域将用于触发文件选择操作，例如点击这个区域可以弹出文件选择对话框等
        id: '#filePickerReady',
        // 设置文件选择区域显示的提示文本为lang.uploadSelectFile（这应该是一个预先定义好的国际化文本变量，用于提示用户选择文件）
        label: lang.uploadSelectFile
    },
    // 指定WebUploader使用的Flash文件路径，这里相对路径指向'../../third-party/webuploader/Uploader.swf'，在某些浏览器不支持HTML5上传时，可能会依赖此Flash文件来实现文件上传功能
    swf: '../../third-party/webuploader/Uploader.swf',
    // 设置文件上传的目标服务器地址，使用之前获取到的actionUrl变量（通过editor相关配置获取的文件上传URL），指定文件要上传到的服务器端接口位置
    server: actionUrl,
    // 设置文件上传时表单中文件对应的字段名，通过调用editor对象的getOpt方法获取'fileFieldName'配置项的值来确定，服务器端会根据这个字段名来接收上传的文件
    fileVal: editor.getOpt('fileFieldName'),
    // 设置是否允许重复选择文件，这里设置为true，表示允许重复选择相同的文件添加到上传队列中
    duplicate: true,
    // 设置单个文件的大小限制，使用之前获取到的fileMaxSize变量（通过editor相关配置获取的允许上传的最大文件大小），用于在选择文件时判断单个文件大小是否超出限制，超出则可能不允许添加到上传队列
    fileSingleSizeLimit: fileMaxSize,
    // 设置是否对文件进行压缩，这里设置为false，表示不对要上传的文件进行压缩处理，直接上传原始文件
    compress: false
});

// 为WebUploader实例添加一个按钮，通过传入一个配置对象来指定按钮相关的设置
// 这里指定按钮对应的DOM元素的id为'filePickerBlock'，具体该按钮的功能和样式等可能在WebUploader内部有默认设置或者后续代码中进一步定义
uploader.addButton({
    id: '#filePickerBlock'
});

// 再次为WebUploader实例添加一个按钮，同样传入配置对象指定按钮相关设置
// 这里指定按钮对应的DOM元素的id为'filePickerBtn'，并且设置按钮显示的提示文本为lang.uploadAddFile（也是预先定义好的国际化文本变量，用于提示用户添加文件）
uploader.addButton({
    id: '#filePickerBtn',
    label: lang.uploadAddFile
});

// 调用setState函数（应该是自定义的用于设置文件上传状态的函数），传入'pedding'（可能表示文件处于等待添加或者初始的准备状态），用于更新和记录当前文件上传的状态
setState('pedding');

// 定义一个名为addFile的函数，当有文件添加到WebUploader实例中时会执行该函数，主要负责创建与该文件对应的视图展示相关元素（比如在页面上展示文件的名称、进度条、操作按钮等信息）
function addFile(file) {
    // 创建一个 <li> 元素，设置其id属性为传入的file对象的id（每个添加的文件应该都有唯一的id标识），并在元素内部添加一些包含文件相关信息的 <p> 元素，用于后续展示文件的名称、图片包装（可能用于展示文件缩略图等）、进度条等内容
    var $li = $('<li id="' + file.id + '">' +
            '<p class="title">' + file.name + '</p>' +
            '<p class="imgWrap"></p>' +
            '<p class="progress"><span></span></p>' +
            '</li>'),

        // 创建一个包含文件操作按钮的 <div> 元素，设置其类名为'file-panel'，内部包含了取消、向右旋转、向左旋转等操作按钮，并将其添加到之前创建的 <li> 元素（$li）中，方便后续对文件进行相应的操作交互
        $btns = $('<div class="file-panel">' +
            '<span class="cancel">' + lang.uploadDelete + '</span>' +
            '<span class="rotateRight">' + lang.uploadTurnRight + '</span>' +
            '<span class="rotateLeft">' + lang.uploadTurnLeft + '</span></div>').appendTo($li),
        // 通过jQuery选择器在创建的 <li> 元素（$li）中查找类名为'progress'的 <p> 元素内部的 <span> 元素，用于后续操作该进度条相关的 <span> 元素（比如更新进度条的显示等），并将找到的元素赋值给变量$prgress
        $prgress = $li.find('p.progress span'),
        // 通过jQuery选择器在创建的 <li> 元素（$li）中查找类名为'imgWrap'的 <p> 元素，用于后续可能在该元素内添加文件的缩略图等操作，将找到的元素赋值给变量$wrap
        $wrap = $li.find('p.imgWrap'),
        // 创建一个用于展示文件错误信息的 <p> 元素，设置其类名为'error'，初始设置为隐藏状态（调用hide方法），然后将其添加到之前创建的 <li> 元素（$li）中，当文件出现错误时可以在该元素内显示相应的错误提示信息
        $info = $('<p class="error"></p>').hide().appendTo($li),

        // 定义一个名为showError的内部函数，用于根据传入的错误代码来显示相应的错误提示文本，通过判断不同的错误代码来设置要显示的具体文本内容（从预先定义好的国际化文本变量中获取相应的提示信息），并将文本显示在之前创建的错误信息元素（$info）中（调用show方法使其显示出来）
        showError = function (code) {
            switch (code) {
                case 'exceed_size':
                    text = lang.errorExceedSize;
                    break;
                case 'interrupt':
                    text = lang.errorInterrupt;
                    break;
                case 'http':
                    text = lang.errorHttp;
                    break;
                case 'not_allow_type':
                    text = lang.errorFileType;
                    break;
                default:
                    text = lang.errorUploadRetry;
                    break;
            }
            $info.text(text).show();
        };

                // 判断文件的状态是否为'invalid'（无效状态，可能表示文件不符合某些上传要求等情况）
if (file.getStatus() === 'invalid') {
    // 如果文件状态为'invalid'，调用showError函数（之前定义的用于显示错误信息的函数），传入文件的statusText（应该是包含具体错误原因等的文本信息），以在页面上展示相应的错误提示给用户
    showError(file.statusText);
} else {
    // 如果文件状态不是'invalid'，则在用于展示文件缩略图等的元素（$wrap）内设置文本内容为lang.uploadPreview（预先定义好的国际化文本变量，用于提示用户正在预览文件之类的信息）
    $wrap.text(lang.uploadPreview);
    // 检查文件的扩展名（file.ext），将其转换为小写形式后，判断是否在指定的图片文件扩展名列表（'|png|jpg|jpeg|bmp|gif|'）中，如果不在（indexOf方法返回 -1表示未找到），说明不是常见的图片文件类型
    if ('|png|jpg|jpeg|bmp|gif|'.indexOf('|'+file.ext.toLowerCase()+'|') == -1) {
        // 如果不是常见图片文件类型，先清空$wrap元素内部的内容（empty方法），然后添加类名'notimage'（可能用于后续设置样式区分非图片文件），接着在该元素内添加一个 <i> 元素（用于展示对应文件类型的图标，通过设置类名来匹配相应的图标样式）以及一个 <span> 元素（用于展示文件名称，并设置title属性同样为文件名称，方便鼠标悬停提示完整文件名）
        $wrap.empty().addClass('notimage').append('<i class="file-preview file-type-' + file.ext.toLowerCase() + '"></i>' +
        '<span class="file-title" title="' + file.name + '">' + file.name + '</span>');
    } else {
        // 如果是常见的图片文件类型，判断当前浏览器是否为IE浏览器（browser.ie为真表示是IE浏览器）并且IE浏览器的版本是否小于等于7（browser.version <= 7）
        if (browser.ie && browser.version <= 7) {
            // 如果是低版本IE浏览器（IE7及以下），则在用于展示文件缩略图等的元素（$wrap）内设置文本内容为lang.uploadNoPreview（预先定义好的国际化文本变量，可能表示该浏览器无法预览此文件之类的信息）
            $wrap.text(lang.uploadNoPreview);
        } else {
            // 如果不是低版本IE浏览器，调用uploader对象（WebUploader实例）的makeThumb方法，用于生成文件的缩略图
            // 传入文件对象（file）、一个回调函数（用于处理生成缩略图的结果，成功时获取到缩略图的源地址等信息，失败时进行相应错误处理）以及缩略图的宽度（thumbnailWidth）和高度（thumbnailHeight）参数
            uploader.makeThumb(file, function (error, src) {
                // 在回调函数内部，判断是否有错误（error为真）或者生成的缩略图源地址（src）为空，说明生成缩略图失败了
                if (error ||!src) {
                    // 如果生成缩略图失败，就在用于展示文件缩略图等的元素（$wrap）内设置文本内容为lang.uploadNoPreview（提示无法预览文件）
                    $wrap.text(lang.uploadNoPreview);
                } else {
                    // 如果生成缩略图成功，创建一个 <img> 元素，设置其src属性为生成的缩略图源地址（src）
                    var $img = $('<img src="' + src + '">');
                    // 先清空$wrap元素内部的内容（empty方法），然后将创建好的 <img> 元素添加到$wrap元素内，用于在页面上展示文件的缩略图
                    $wrap.empty().append($img);
                    // 为添加的 <img> 元素绑定error事件处理函数，当图片加载出现错误（比如图片地址无效、网络问题等导致无法显示图片）时触发该函数
                    $img.on('error', function () {
                        // 在图片加载出错时，同样在用于展示文件缩略图等的元素（$wrap）内设置文本内容为lang.uploadNoPreview（提示无法预览文件）
                        $wrap.text(lang.uploadNoPreview);
                    });
                }
            }, thumbnailWidth, thumbnailHeight);
        }
    }
    // 创建一个数组，将文件的大小（file.size）和初始进度值0作为元素放入数组中，然后以文件的id为键，将这个数组存储到percentages对象中，用于记录每个文件的大小以及后续更新其上传进度情况
    percentages[ file.id ] = [ file.size, 0 ];
    // 初始化文件的旋转角度为0，可能用于后续支持文件旋转相关的操作（比如图片旋转等功能）
    file.rotation = 0;

    /* 检查文件格式 */
    // 判断文件的扩展名（file.ext）是否为空或者文件的扩展名（转换为小写形式后）在允许上传的文件扩展名列表（acceptExtensions）中是否不存在（indexOf方法返回 -1表示不存在），也就是检查文件格式是否符合允许上传的要求
    if (!file.ext || acceptExtensions.indexOf(file.ext.toLowerCase()) == -1) {
        // 如果文件格式不符合要求，调用showError函数，传入'not_allow_type'（表示文件类型不允许上传的错误代码），以显示相应的错误提示信息，告知用户文件类型不被允许上传
        showError('not_allow_type');
        // 调用uploader对象（WebUploader实例）的removeFile方法，将不符合文件格式要求的文件从上传队列中移除，避免上传不符合规定的文件
        uploader.removeFile(file);
    }
}

// 为文件对象绑定'statuschange'事件处理函数，当文件的状态发生改变时会触发该函数，传入当前状态（cur）和之前的状态（prev）作为参数，用于根据不同的状态变化执行相应的操作
file.on('statuschange', function (cur, prev) {
    // 如果文件之前的状态（prev）是'progress'（表示正在上传进度中）
    if (prev === 'progress') {
        // 隐藏用于展示文件上传进度的元素（$prgress），并将其宽度设置为0，可能用于重置进度条的显示，比如上传中断等情况需要重新展示进度时先进行这样的重置操作
        $prgress.hide().width(0);
    } else if (prev === 'queued') {
        // 如果文件之前的状态是'queued'（表示已添加到上传队列中等待上传），则移除为 <li> 元素（$li，代表文件对应的整个展示元素）绑定的鼠标进入（mouseenter）和鼠标离开（mouseleave）事件处理函数（off方法用于移除事件绑定），同时移除文件操作按钮所在的 <div> 元素（$btns），可能是在文件进入下一个阶段（比如开始上传等）时不需要这些交互元素或者需要重新绑定不同的交互逻辑了
        $li.off('mouseenter mouseleave');
        $btns.remove();
    }
    // 如果文件当前状态（cur）是'error'（表示出现错误）或者'invalid'（无效状态）
    if (cur === 'error' || cur === 'invalid') {
        // 调用showError函数，传入文件的statusText（包含具体错误原因等的文本信息），以在页面上展示相应的错误提示给用户，告知文件出现错误的情况
        showError(file.statusText);
        // 将文件在percentages对象中记录的进度值（数组中的第二个元素）设置为1，表示出现错误后认为文件上传已完成（但实际上是失败了），可能用于更新界面上进度相关的显示等情况
        percentages[ file.id ][ 1 ] = 1;
    } else if (cur === 'interrupt') {
        // 如果文件当前状态是'interrupt'（表示上传被中断），调用showError函数，传入'interrupt'（表示上传中断的错误代码），以显示相应的错误提示信息，告知用户文件上传被中断了
        showError('interrupt');
    } else if (cur === 'queued') {
        // 如果文件当前状态是'queued'（表示重新回到已添加到上传队列等待上传的状态，可能是之前出现问题后重新排队等情况），将文件在percentages对象中记录的进度值（数组中的第二个元素）设置为0，重置文件的上传进度为初始的等待上传状态，用于更新界面上进度相关的显示等情况
        percentages[ file.id ][ 1 ] = 0;
    } else if (cur === 'progress') {
        // 如果文件当前状态是'progress'（表示正在上传进度中），隐藏之前创建的用于展示文件错误信息的元素（$info，可能在上传过程中之前出现的错误提示等不需要显示了），并将用于展示文件上传进度的元素（$prgress）的display样式属性设置为'block'，使其显示出来，以展示当前文件正在上传的进度情况
        $info.hide();
        $prgress.css('display', 'block');
    } else if (cur === 'complete') {
        // 如果文件当前状态是'complete'（表示文件上传完成），这里暂时没有具体的操作，可能后续需要添加如更新界面显示完成状态、提示用户上传成功等相关操作逻辑，具体根据业务需求而定
    }

                    // 根据文件状态变化，移除文件对应的 <li> 元素（$li）上之前表示状态的类名（格式为'state-' + prev，prev是文件之前的状态），然后添加表示当前状态的类名（格式为'state-' + cur，cur是文件当前的状态），这样可以通过不同的类名来应用相应的样式，以体现文件在不同状态下的外观变化（例如不同状态下的颜色、图标显示等不同样式效果）
$li.removeClass('state-' + prev).addClass('state-' + cur);
// 为文件对应的 <li> 元素（$li）绑定鼠标进入（mouseenter）事件处理函数，当鼠标移入该元素时触发此函数
$li.on('mouseenter', function () {
    // 当鼠标移入时，找到文件操作按钮所在的 <div> 元素（$btns），先调用stop方法停止正在进行的动画（如果有的话，避免动画队列堆积等问题），然后调用animate方法触发一个动画效果，将该元素的高度从当前值渐变到30像素，实现鼠标移入时按钮区域展开显示的交互效果，方便用户操作按钮
    $btns.stop().animate({height: 30});
});
// 为文件对应的 <li> 元素（$li）绑定鼠标离开（mouseleave）事件处理函数，当鼠标移出该元素时触发此函数
$li.on('mouseleave', function () {
    // 当鼠标移出时，找到文件操作按钮所在的 <div> 元素（$btns），同样先调用stop方法停止正在进行的动画，然后调用animate方法触发一个动画效果，将该元素的高度从当前值渐变到0像素，实现鼠标移出时按钮区域收缩隐藏的交互效果，保持页面的简洁性和美观性
    $btns.stop().animate({height: 0});
});

// 为文件操作按钮所在的 <div> 元素（$btns）绑定点击（click）事件处理函数，并且通过第二个参数'span'指定只监听 <div> 元素内部的 <span> 元素（也就是各个具体的操作按钮）的点击事件
$btns.on('click', 'span', function () {
    // 获取被点击的 <span> 元素（也就是具体的操作按钮）在其兄弟元素中的索引位置，用于区分不同的按钮，赋值给变量index，例如索引为0可能是删除按钮，索引为1可能是向右旋转按钮等
    var index = $(this).index(),
        deg;

    // 根据按钮的索引（index）值进行不同的操作，通过switch语句来区分不同的按钮点击情况
    switch (index) {
        // 如果索引为0，说明点击的是第一个按钮（通常是删除按钮之类的功能）
        case 0:
            // 调用uploader对象（WebUploader实例）的removeFile方法，传入当前文件对象（file），将该文件从上传队列中移除，实现删除文件的功能
            uploader.removeFile(file);
            // 执行完删除操作后，直接返回，不再执行后续的代码，因为文件已经被删除，不需要再进行其他与该文件相关的操作了
            return;
        // 如果索引为1，说明点击的是第二个按钮（可能是向右旋转按钮之类的功能）
        case 1:
            // 将文件的旋转角度（file.rotation）增加90度，用于记录文件旋转的状态变化，后续可能根据这个角度来实际旋转文件的展示效果（比如图片旋转等）
            file.rotation += 90;
            break;
        // 如果索引为2，说明点击的是第三个按钮（可能是向左旋转按钮之类的功能）
        case 2:
            // 将文件的旋转角度（file.rotation）减少90度，同样是用于记录文件旋转的状态变化，以便后续实现相应的展示效果调整
            file.rotation -= 90;
            break;
    }

    // 判断浏览器是否支持CSS过渡效果（supportTransition为真表示支持），如果支持
    if (supportTransition) {
        // 根据文件当前的旋转角度（file.rotation）构建一个CSS变换（transform）的旋转样式值，格式为'rotate(' + file.rotation + 'deg)'，用于后续设置元素的旋转效果，赋值给变量deg
        deg = 'rotate(' + file.rotation + 'deg)';
        // 找到用于展示文件缩略图等的元素（$wrap），通过css方法设置其多个浏览器前缀版本的CSS变换属性（-webkit-transform、-mos-transform、-o-transform以及标准的transform），都设置为刚刚构建的旋转样式值（deg），从而实现在支持CSS过渡效果的浏览器中通过CSS变换来旋转文件展示元素（比如图片），达到视觉上的旋转效果
        $wrap.css({
            '-webkit-transform': deg,
            '-mos-transform': deg,
            '-o-transform': deg,
            'transform': deg
        });
    } else {
        // 如果浏览器不支持CSS过渡效果，通过设置IE浏览器的滤镜（filter）属性来实现文件展示元素（$wrap）的旋转效果，使用特定的IE滤镜语法'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + (~~((file.rotation / 90) % 4 + 4) % 4) + ')'，其中通过一些数学运算来将文件的旋转角度转换为IE滤镜能识别的旋转参数值，以实现在不支持CSS过渡效果的IE浏览器中也能进行文件展示元素的旋转操作（虽然这种方式相对较旧且兼容性有限，但用于应对旧版本IE浏览器的特殊情况）
        $wrap.css('filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + (~~((file.rotation / 90) % 4 + 4) % 4) + ')');
    }

});

// 将文件对应的 <li> 元素（$li）插入到id为$filePickerBlock的元素之前，这样可以调整文件展示元素在页面中的排列顺序，例如将新添加的文件展示元素显示在文件选择相关区域之前等，方便用户查看和操作文件相关信息
$li.insertBefore($filePickerBlock);
}

// 定义一个名为removeFile的函数，用于销毁与文件相关的视图元素以及清理相关的数据等操作，也就是负责文件相关视图的销毁工作
function removeFile(file) {
    // 通过文件的id找到对应的 <li> 元素，赋值给变量$li，后续将基于这个元素进行相关的销毁和清理操作
    var $li = $('#' + file.id);
    // 从percentages对象中删除以该文件的id为键的数据，也就是移除记录该文件大小和进度等信息的数据项，因为文件要被销毁了，相关进度等信息不再需要保留
    delete percentages[ file.id ];
    // 调用updateTotalProgress函数（用于更新总体上传进度相关的显示等情况），在移除文件后及时更新整体的进度信息，确保界面上显示的进度情况是准确的
    updateTotalProgress();
    // 对找到的 <li> 元素（$li）进行一系列操作，先调用off方法移除该元素上绑定的所有事件处理函数（避免内存泄漏以及不必要的事件触发等问题），然后找到该元素内部的.file-panel类元素（也就是文件操作按钮所在的 <div> 元素），同样调用off方法移除其绑定的所有事件处理函数，最后调用end方法回到最初的 <li> 元素，并调用remove方法将该 <li> 元素从DOM树中移除，彻底销毁与该文件相关的视图元素
    $li.off().find('.file-panel').off().end().remove();
}

// 定义一个名为updateTotalProgress的函数，用于更新文件上传的总体进度信息，并根据进度情况更新界面上相关元素的显示内容（如进度条的百分比显示等）
function updateTotalProgress() {
    // 初始化一个变量loaded，用于记录已经上传的文件大小总和，初始值设为0
    var loaded = 0,
        // 初始化一个变量total，用于记录所有文件的总大小，初始值设为0
        total = 0,
        // 通过jQuery选择器找到总体进度条（$progress）元素内部的所有子元素（可能是用于展示进度文本和进度条宽度的元素等），赋值给变量spans，方便后续操作这些子元素来更新进度显示
        spans = $progress.children(),
        percent;

    // 使用jQuery的each方法遍历percentages对象（记录每个文件的大小和进度信息的对象），对于每个键值对（文件id作为键k，文件大小和进度数组作为值v）进行操作
    $.each(percentages, function (k, v) {
        // 将当前文件的大小（v[0]）累加到total变量中，用于计算所有文件的总大小
        total += v[ 0 ];
        // 根据当前文件的大小（v[0]）和当前文件的上传进度（v[1]）计算已经上传的该文件的大小部分（即文件大小乘以进度百分比），并累加到loaded变量中，用于计算所有文件已经上传的总大小
        loaded += v[ 0 ] * v[ 1 ];
    });

    // 计算总体上传进度百分比，通过判断总大小（total）是否为0来避免除数为0的情况，如果总大小不为0，则用已经上传的总大小（loaded）除以总大小（total）得到进度百分比，否则进度百分比设为0
    percent = total? loaded / total : 0;

    // 找到总体进度条元素（$progress）的第一个子元素（可能是用于展示进度百分比文本的元素），调用text方法将计算得到的进度百分比转换为整数并拼接上 '%' 符号后设置为其文本内容，用于在界面上显示总体上传进度的百分比数值
    spans.eq(0).text(Math.round(percent * 100) + '%');
    // 找到总体进度条元素（$progress）的第二个子元素（可能是用于展示进度条实际宽度的元素），调用css方法设置其宽度样式属性，将计算得到的进度百分比转换为整数并拼接上 '%' 符号后设置为宽度值，以通过改变宽度来直观展示总体上传进度的情况（例如进度条的填充长度等视觉效果）
    spans.eq(1).css('width', Math.round(percent * 100) + '%');
    // 调用updateStatus函数（应该是用于更新文件上传相关的其他状态显示等情况的函数，虽然此处未展示其具体代码，但从函数名推测其功能），在更新完进度信息后，进一步更新其他相关的状态显示内容，确保界面上展示的文件上传状态是完整且准确的
    updateStatus();
}

          // 定义一个名为setState的函数，用于设置文件上传过程中的状态，并根据不同状态进行相应的界面元素显示、隐藏以及样式调整等操作，接收两个参数，val表示要设置的目标状态值，files参数（此处从代码来看暂未明确具体使用方式，但可能与文件相关，比如特定的文件列表等）
function setState(val, files) {

    // 判断传入的要设置的目标状态值（val）与当前的状态（state，应该是在函数外部定义的用于记录当前文件上传状态的变量）是否不相等，如果不相等，说明状态发生了变化，需要执行相应的状态更新操作
    if (val!= state) {

        // 调用uploader对象（WebUploader实例）的getStats方法，获取文件上传的统计信息（比如已上传成功的文件数量、失败的文件数量等各种状态相关的数据），并将结果赋值给变量stats，用于后续根据不同状态判断并进行相应的界面操作
        var stats = uploader.getStats();

        // 移除上传按钮（$upload）上表示当前状态的类名（格式为'state-' + state，state是之前的状态），用于去除之前状态对应的样式，以便后续添加新状态对应的样式
        $upload.removeClass('state-' + state);
        // 为上传按钮（$upload）添加表示目标状态（val）的类名（格式为'state-' + val），通过添加不同的类名可以应用不同的样式（例如按钮的文本、颜色、可操作性等样式变化）来体现当前文件上传所处的不同状态
        $upload.addClass('state-' + val);

        // 根据传入的目标状态值（val）进行不同的操作，通过switch语句来区分不同的状态情况
        switch (val) {

            /* 未选择文件 */
            case 'pedding':
                // 为文件列表所在的元素（$queue）添加类名'element-invisible'，这个类名可能在CSS中定义了相应的样式用于隐藏元素（比如设置display:none或者visibility:hidden等），使文件列表在未选择文件时隐藏起来，符合此时的状态展示需求
                $queue.addClass('element-invisible');
                // 为状态栏元素（$statusBar）添加类名'element-invisible'，同样使其隐藏起来，因为在未选择文件时，状态栏相关的进度、信息等展示可能不需要显示
                $statusBar.addClass('element-invisible');
                // 移除占位元素（$placeHolder）上的类名'element-invisible'，也就是让占位元素显示出来，可能用于在未选择文件时展示一些提示用户选择文件之类的信息（例如“请选择要上传的文件”等提示语所在的元素）
                $placeHolder.removeClass('element-invisible');
                // 隐藏总体进度条元素（$progress），因为在未选择文件状态下不需要展示进度相关信息，调用hide方法实现隐藏效果
                $progress.hide();
                // 隐藏文件总体选择信息元素（$info），同样此时不需要展示相关的文件选择等信息，进行隐藏操作
                $info.hide();
                // 调用uploader对象（WebUploader实例）的refresh方法，可能用于刷新WebUploader内部的一些状态或者界面相关的显示情况，确保在状态切换时其内部状态与界面展示保持一致，具体功能取决于WebUploader的实现逻辑
                uploader.refresh();
                break;

            /* 可以开始上传 */
            case 'ready':
                // 为占位元素（$placeHolder）添加类名'element-invisible'，使其隐藏起来，因为此时已经可以开始上传文件了，不需要再显示占位提示信息等内容
                $placeHolder.addClass('element-invisible');
                // 移除文件列表所在元素（$queue）的类名'element-invisible'，让文件列表显示出来，方便用户查看已经添加到上传队列中的文件信息
                $queue.removeClass('element-invisible');
                // 移除状态栏元素（$statusBar）的类名'element-invisible'，使状态栏显示出来，用于展示文件上传相关的进度、信息等内容
                $statusBar.removeClass('element-invisible');
                // 隐藏总体进度条元素（$progress），因为此时虽然可以上传但还未真正开始上传，不需要展示进度情况，先隐藏起来
                $progress.hide();
                // 显示文件总体选择信息元素（$info），用于展示如已选择文件的数量、大小等相关信息，让用户了解当前的文件选择情况
                $info.show();
                // 设置上传按钮（$upload）的文本内容为lang.uploadStart（预先定义好的国际化文本变量，可能表示“开始上传”之类的提示语），提示用户可以点击按钮进行文件上传操作了
                $upload.text(lang.uploadStart);
                // 调用uploader对象（WebUploader实例）的refresh方法，刷新WebUploader内部状态及界面显示情况，确保在进入可上传状态时相关展示是准确的
                uploader.refresh();
                break;

            /* 上传中 */
            case 'uploading':
                // 显示总体进度条元素（$progress），因为文件正在上传，需要展示上传的进度情况给用户，调用show方法使其显示出来
                $progress.show();
                // 隐藏文件总体选择信息元素（$info），在上传过程中可能不需要展示文件选择相关信息了，将其隐藏
                $info.hide();
                // 设置上传按钮（$upload）的文本内容为lang.uploadPause（预先定义好的国际化文本变量，可能表示“暂停上传”之类的提示语），提示用户此时点击按钮可以暂停正在进行的文件上传操作
                $upload.text(lang.uploadPause);
                break;

            /* 暂停上传 */
            case 'paused':
                // 显示总体进度条元素（$progress），虽然上传暂停了，但仍可以展示之前已经上传的进度情况等信息，所以使其显示出来
                $progress.show();
                // 隐藏文件总体选择信息元素（$info），同样在暂停状态下可能不需要展示该信息，进行隐藏操作
                $info.hide();
                // 设置上传按钮（$upload）的文本内容为lang.uploadContinue（预先定义好的国际化文本变量，可能表示“继续上传”之类的提示语），提示用户点击按钮可以继续之前暂停的文件上传操作
                $upload.text(lang.uploadContinue);
                break;

            case 'confirm':
                // 显示总体进度条元素（$progress），用于展示上传的进度情况，调用show方法使其显示出来
                $progress.show();
                // 隐藏文件总体选择信息元素（$info），可能在这个确认状态下不需要展示该信息，进行隐藏操作
                $progress.show(); $info.hide();
                // 设置上传按钮（$upload）的文本内容为lang.uploadStart（预先定义好的国际化文本变量，可能表示“开始上传”之类的提示语），此处设置这个文本可能是根据业务逻辑，在确认相关情况后可以再次开始上传之类的操作
                $upload.text(lang.uploadStart);

                // 再次获取文件上传的统计信息（stats），可能前面的操作过程中相关统计数据有变化，重新获取最新数据用于后续判断
                stats = uploader.getStats();
                // 判断如果已经上传成功的文件数量（stats.successNum）大于0且上传失败的文件数量（stats.uploadFailNum）为0，也就是所有文件都上传成功了的情况
                if (stats.successNum &&!stats.uploadFailNum) {
                    // 调用setState函数，传入'finish'作为状态值，将文件上传状态设置为完成状态，进入完成状态相关的界面展示和操作逻辑，然后直接返回，不再执行后续switch语句中的其他代码，因为已经完成了状态的最终切换
                    setState('finish');
                    return;
                }
                break;

            case 'finish':
                // 隐藏总体进度条元素（$progress），因为文件上传已经完成，不需要再展示进度信息了，调用hide方法进行隐藏操作
                $progress.hide();
                // 显示文件总体选择信息元素（$info），可能用于展示一些如上传完成的提示信息或者最终的文件上传结果相关内容等，调用show方法使其显示出来
                $info.show();
                // 判断如果上传失败的文件数量（stats.uploadFailNum）大于0，也就是存在文件上传失败的情况
                if (stats.uploadFailNum) {
                    // 设置上传按钮（$upload）的文本内容为lang.uploadRetry（预先定义好的国际化文本变量，可能表示“重试上传”之类的提示语），提示用户可以点击按钮重新尝试上传失败的文件
                    $upload.text(lang.uploadRetry);
                } else {
                    // 如果没有文件上传失败，设置上传按钮（$upload）的文本内容为lang.uploadStart（预先定义好的国际化文本变量，可能表示“开始上传”之类的提示语），可能用于提示用户可以继续上传新的文件等操作，具体根据业务逻辑而定
                    $upload.text(lang.uploadStart);
                }
                break;
        }

        // 将当前的状态（state）更新为传入的目标状态值（val），确保记录的状态与实际设置的状态保持一致，方便后续其他函数根据这个状态变量进行相应的操作判断
        state = val;
        // 调用updateStatus函数（应该是用于更新文件上传相关的其他一些状态显示、界面调整等操作的函数，虽然此处未展示其具体代码，但从函数名推测其功能），在状态更新后进一步确保整个文件上传界面展示的状态是完整且准确的
        updateStatus();

    }
// 判断当前实例对象（_this）通过调用getQueueCount方法获取的上传队列中的文件数量是否为0，如果是0，表示上传队列中没有文件
if (!_this.getQueueCount()) {
    // 如果上传队列中没有文件，为上传按钮（$upload）添加类名'disabled'，这个类名可能在CSS中定义了相应的样式（比如设置按钮为不可点击状态、改变按钮颜色等外观样式来表示不可用），用于提示用户当前无法进行上传操作，因为没有文件在队列中等待上传
    $upload.addClass('disabled')
} else {
    // 如果上传队列中文件数量不为0，也就是有文件在队列中等待上传，移除上传按钮（$upload）上的类名'disabled'，使按钮恢复可操作的正常样式（例如可以点击进行上传等操作）
    $upload.removeClass('disabled')
}

// 定义一个名为updateStatus的函数，用于更新文件上传相关的状态信息展示内容，比如在页面上的特定元素中显示不同状态下的提示文本，告知用户当前文件上传的进展、结果等情况
function updateStatus() {
    // 初始化一个变量text，用于存储要展示的状态信息文本内容，初始为空字符串，后续会根据不同的文件上传状态进行相应的文本拼接和替换操作来生成最终要展示的文本
    var text = '', stats;

    // 判断当前文件上传状态（state）是否为'ready'（表示可以开始上传的状态）
    if (state === 'ready') {
        // 如果是'ready'状态，使用lang.updateStatusReady（预先定义好的国际化文本变量，应该是包含占位符的文本模板，用于展示准备上传状态相关信息），通过replace方法将其中的'_'占位符替换为实际的已添加到队列中的文件数量（fileCount），再将'_KB'占位符替换为通过WebUploader.formatSize方法（应该是WebUploader提供的用于格式化文件大小显示格式的函数）格式化后的文件总大小（fileSize），最终得到符合当前状态且展示具体文件数量和总大小信息的文本内容，赋值给text变量
        text = lang.updateStatusReady.replace('_', fileCount).replace('_KB', WebUploader.formatSize(fileSize));
    } else if (state === 'confirm') {
        // 如果当前文件上传状态是'confirm'（可能表示某种确认状态，例如确认上传结果等情况），先获取文件上传的统计信息（通过调用uploader.getStats方法），并将结果赋值给stats变量，用于后续判断上传成功和失败的文件数量等情况
        stats = uploader.getStats();
        // 判断如果上传失败的文件数量（stats.uploadFailNum）大于0，也就是存在文件上传失败的情况
        if (stats.uploadFailNum) {
            // 使用lang.updateStatusConfirm（同样是预先定义好的国际化文本变量，包含占位符的文本模板，用于展示确认状态相关信息），通过replace方法将其中的'_'占位符替换为实际的上传成功的文件数量（stats.successNum），这里替换了两次，可能根据具体文本模板的格式需求来准确展示相关信息，最终生成符合当前状态且体现上传成功文件数量的文本内容，赋值给text变量
            text = lang.updateStatusConfirm.replace('_', stats.successNum).replace('_', stats.successNum);
        }
    } else {
        // 如果当前文件上传状态不是'ready'也不是'confirm'，也就是其他状态情况（例如完成状态等），先获取文件上传的统计信息（调用uploader.getStats方法），并将结果赋值给stats变量
        stats = uploader.getStats();
        // 使用lang.updateStatusFinish（预先定义好的国际化文本变量，包含占位符的文本模板，用于展示完成状态相关信息），通过replace方法依次进行占位符替换操作：
        // 将第一个'_'占位符替换为实际的已添加到队列中的文件数量（fileCount），
        // 将'_KB'占位符替换为通过WebUploader.formatSize方法格式化后的文件总大小（fileSize），
        // 将第二个'_'占位符替换为实际的上传成功的文件数量（stats.successNum），
        // 经过这些替换操作后，生成符合当前状态且展示文件数量、总大小以及上传成功文件数量等信息的文本内容，赋值给text变量
        text = lang.updateStatusFinish.replace('_', fileCount).
            replace('_KB', WebUploader.formatSize(fileSize)).
            replace('_', stats.successNum);

        // 判断如果上传失败的文件数量（stats.uploadFailNum）大于0，也就是存在文件上传失败的情况
        if (stats.uploadFailNum) {
            // 将预先定义好的用于展示错误信息的国际化文本变量lang.updateStatusError（同样包含占位符的文本模板，用于在有文件上传失败时补充相关错误信息），通过replace方法将其中的'_'占位符替换为实际的上传失败的文件数量（stats.uploadFailNum），然后将生成的包含失败文件数量的错误提示文本追加到之前生成的text变量内容后面，用于完整展示包含上传成功和失败文件数量等详细情况的最终状态信息文本
            text += lang.updateStatusError.replace('_', stats.uploadFailNum);
        }
    }

    // 找到用于展示文件总体选择信息的元素（$info），通过html方法将刚刚生成的text变量中的文本内容设置为该元素的HTML内容，从而在页面上相应位置展示出更新后的文件上传状态信息，让用户了解当前的上传情况
    $info.html(text);
}

// 为uploader对象（WebUploader实例）绑定'fileQueued'事件处理函数，当有单个文件添加到上传队列时会触发该函数，传入添加的文件对象（file）作为参数，用于处理文件添加到队列后的相关操作，比如更新文件数量、文件总大小等信息以及创建文件对应的视图展示元素等
uploader.on('fileQueued', function (file) {
    // 判断文件的扩展名（file.ext）是否存在，并且文件的扩展名（转换为小写形式后）在允许上传的文件扩展名列表（acceptExtensions）中是否能找到（indexOf方法返回值不为 -1表示存在），同时判断文件大小（file.size）是否小于等于允许上传的单个文件最大大小限制（fileMaxSize），也就是检查文件是否符合上传要求
    if (file.ext && acceptExtensions.indexOf(file.ext.toLowerCase())!= -1 && file.size <= fileMaxSize) {
        // 如果文件符合上传要求，将记录已添加到队列中的文件数量的变量（fileCount）加1，用于统计上传队列中的文件数量变化情况
        fileCount++;
        // 将当前文件的大小（file.size）累加到记录文件总大小的变量（fileSize）中，用于实时更新所有已添加到队列中的文件的总大小情况
        fileSize += file.size;
    }

    // 判断如果上传队列中的文件数量（fileCount）等于1，也就是刚刚添加了第一个符合要求的文件到队列中时
    if (fileCount === 1) {
        // 为占位元素（$placeHolder，可能是在还未添加文件时显示提示用户选择文件等信息的元素）添加类名'element-invisible'，使其隐藏起来，因为已经有文件添加到队列了，不需要再显示占位提示信息了
        $placeHolder.addClass('element-invisible');
        // 显示状态栏元素（$statusBar，用于展示文件上传相关的进度、信息等内容），使其显示出来，方便用户查看文件上传相关的情况，因为有文件在队列中了，需要展示相应的状态信息了
        $statusBar.show();
    }

    // 调用addFile函数（之前定义的用于创建与文件对应的视图展示元素等操作的函数），传入当前添加的文件对象（file），为该文件创建相应的展示元素（如文件名称、进度条、操作按钮等元素）并添加到页面中，方便用户查看和操作该文件
    addFile(file);
});

// 为uploader对象（WebUploader实例）绑定'fileDequeued'事件处理函数，当有单个文件从上传队列中移除时会触发该函数，传入被移除的文件对象（file）作为参数，用于处理文件移除后的相关操作，比如更新文件数量、文件总大小等信息以及销毁文件对应的视图展示元素等
uploader.on('fileDequeued', function (file) {
    // 判断文件的扩展名（file.ext）是否存在，并且文件的扩展名（转换为小写形式后）在允许上传的文件扩展名列表（acceptExtensions）中是否能找到（indexOf方法返回值不为 -1表示存在），同时判断文件大小（file.size）是否小于等于允许上传的单个文件最大大小限制（fileMaxSize），也就是检查被移除的这个文件是否原本是符合上传要求的文件（进行相应的数量和大小统计调整时需要确认是符合要求的文件）
    if (file.ext && acceptExtensions.indexOf(file.ext.toLowerCase())!= -1 && file.size <= fileMaxSize) {
        // 如果被移除的文件符合上传要求，将记录已添加到队列中的文件数量的变量（fileCount）减1，用于统计上传队列中的文件数量变化情况，因为有文件被移除了
        fileCount--;
        // 将当前文件的大小（file.size）从记录文件总大小的变量（fileSize）中减去，用于实时更新所有已添加到队列中的文件的总大小情况，因为有文件的大小需要从总大小中扣除了
        fileSize -= file.size;
    }

    // 调用removeFile函数（之前定义的用于销毁文件相关视图元素以及清理相关数据等操作的函数），传入当前被移除的文件对象（file），执行销毁文件对应展示元素、清理相关数据（如移除记录该文件进度等信息的数据项）等操作，确保页面展示和相关数据与实际队列情况一致
    removeFile(file);
    // 调用updateTotalProgress函数（之前定义的用于更新文件上传的总体进度信息以及相关界面显示的函数），在文件移除后及时更新整体的进度信息以及相应的界面展示情况，保证展示给用户的上传进度等信息是准确的
    updateTotalProgress();
});

// 为uploader对象（WebUploader实例）绑定'filesQueued'事件处理函数，当有多个文件添加到上传队列时会触发该函数，传入添加的文件对象（file）作为参数（虽然这里参数名和单个文件添加时一样，但实际传入的可能是多个文件组成的集合之类的情况，具体取决于WebUploader的实现方式），用于处理多个文件添加到队列后的相关状态判断和操作，比如根据当前状态判断是否可以切换到可上传状态等情况
uploader.on('filesQueued', function (file) {
    // 判断uploader对象（WebUploader实例）当前是否正在进行上传操作（通过调用isInProgress方法判断，返回false表示不在进行中），并且当前文件上传状态（state）是'pedding'（未选择文件状态）、'finish'（完成状态）、'confirm'（确认状态）或者'ready'（可开始上传状态）中的任意一种情况，也就是判断在合适的状态下且当前没有正在上传时，有新文件添加进来的情况
    if (!uploader.isInProgress() && (state == 'pedding' || state == 'finish' || state == 'confirm' || state == 'ready')) {
        // 如果满足上述条件，调用setState函数，传入'ready'作为状态值，将文件上传状态设置为可以开始上传的状态，方便用户能及时进行上传操作，更新相关的界面元素显示和状态信息展示等情况
        setState('ready');
    }
    // 调用updateTotalProgress函数，在多个文件添加到队列后及时更新文件上传的总体进度信息以及相应的界面展示情况，确保展示给用户的进度等信息是准确的，反映最新的文件队列情况
    updateTotalProgress();
});
          // 为uploader对象（WebUploader实例）绑定'all'事件处理函数，'all'事件会在多种不同的上传相关事件触发时都会被调用，传入事件类型（type）和相关文件对象（files，可能是单个文件对象或者多个文件对象组成的集合，取决于具体触发的事件情况）作为参数，用于根据不同的具体事件类型执行相应的操作
uploader.on('all', function (type, files) {
    // 根据传入的事件类型（type）进行不同的操作，通过switch语句来区分不同的事件情况
    switch (type) {
        // 如果事件类型是'uploadFinished'，表示文件上传已经全部完成（所有文件都完成了上传操作）
        case 'uploadFinished':
            // 调用setState函数，传入'confirm'作为状态值，同时传入相关文件对象（files），将文件上传状态设置为确认状态（可能用于后续确认上传结果、进行相关统计等操作），并根据这个状态切换来更新界面元素显示、状态信息展示等情况
            setState('confirm', files);
            break;
        // 如果事件类型是'startUpload'，表示开始上传文件操作即将启动
        case 'startUpload':
            /* 添加额外的GET参数 */
            // 通过调用utils对象的serializeParam函数（应该是用于序列化参数的自定义函数），传入editor对象的queryCommandValue方法获取'serverparam'命令对应的值（可能是一些自定义的服务器端相关参数），将返回结果赋值给params变量，如果返回结果为空（也就是没有获取到参数），则params为空字符串，用于后续构建包含额外参数的上传URL
            var params = utils.serializeParam(editor.queryCommandValue('serverparam')) || '',
                // 通过调用utils对象的formatUrl函数（应该是用于格式化URL的自定义函数），构建一个新的上传URL地址，在原有的actionUrl（文件上传的基础目标URL地址）基础上，根据其是否已经包含查询字符串（通过判断是否存在'?'来确定），添加合适的连接符号（如果没有查询字符串则添加'?'，已有则添加'&'），然后拼接上固定的'encode=utf-8&'以及前面获取到的参数（params），最终生成包含额外GET参数的完整上传URL地址，赋值给url变量
                url = utils.formatUrl(actionUrl + (actionUrl.indexOf('?') == -1? '?':'&') + 'encode=utf-8&' + params);
            // 调用uploader对象（WebUploader实例）的option方法，传入'server'作为配置项名称，将前面构建好的包含额外参数的上传URL地址（url）设置为新的文件上传服务器地址，用于实际的文件上传请求将按照这个更新后的URL进行发送
            uploader.option('server', url);
            // 调用setState函数，传入'uploading'作为状态值，同时传入相关文件对象（files），将文件上传状态设置为正在上传状态，并且根据这个状态切换来更新界面元素显示（比如显示进度条等）、状态信息展示等情况，告知用户文件正在上传过程中
            setState('uploading', files);
            break;
        // 如果事件类型是'stopUpload'，表示文件上传操作被停止（例如用户点击了暂停按钮等情况导致上传停止）
        case 'stopUpload':
            // 调用setState函数，传入'paused'作为状态值，同时传入相关文件对象（files），将文件上传状态设置为暂停状态，然后根据这个状态切换来更新界面元素显示（比如保持进度条显示等）、状态信息展示等情况，提示用户上传已暂停，可进行相应操作（如继续上传等）
            setState('paused', files);
            break;
    }
});

// 为uploader对象（WebUploader实例）绑定'uploadBeforeSend'事件处理函数，当在文件上传即将发送请求之前会触发该函数，传入即将上传的文件对象（file）、用于存放POST请求参数的数据对象（data，可在这个对象中添加额外的POST参数）以及请求头对象（header，可用于设置请求头相关的信息）作为参数，用于在上传前进行一些请求相关的配置操作
uploader.on('uploadBeforeSend', function (file, data, header) {
    // 这里可以通过data对象添加POST参数，也就是在文件上传前，如果有需要向服务器端传递额外的POST数据，可以在这个函数内部操作data对象来添加相应的参数信息（具体添加哪些参数根据业务需求而定）

    // 判断文件上传的目标URL地址（actionUrl）转换为小写形式后，是否包含'jsp'字符串，如果包含（indexOf方法返回值不为 -1），说明可能是向JSP相关的服务器端接口上传文件
    if (actionUrl.toLowerCase().indexOf('jsp')!= -1) {
        // 如果是向JSP相关的服务器端接口上传文件，在请求头对象（header）中添加一个名为'X_Requested_With'的属性，设置其值为'XMLHttpRequest'，这是一种常见的设置，用于标识该请求是通过XMLHttpRequest方式发起的，可能用于服务器端识别请求来源或者进行相应的处理逻辑判断等情况
        header['X_Requested_With'] = 'XMLHttpRequest';
    }
});

// 为uploader对象（WebUploader实例）绑定'uploadProgress'事件处理函数，在文件上传过程中，当某个文件的上传进度有更新时会触发该函数，传入正在上传的文件对象（file）以及该文件当前的上传进度百分比（percentage）作为参数，用于更新界面上该文件的进度条显示以及整体的上传进度统计等相关信息
uploader.on('uploadProgress', function (file, percentage) {
    // 通过文件的id找到对应的 <li> 元素（也就是该文件在页面上对应的整个展示元素），赋值给变量$li，方便后续操作该元素内部的进度条相关元素来更新显示
    var $li = $('#' + file.id),
        // 通过jQuery选择器在找到的 <li> 元素（$li）中查找类名为'progress'的 <p> 元素内部的 <span> 元素（也就是用于展示该文件上传进度条的具体元素），赋值给变量$percent，用于后续操作该进度条元素来更新其宽度等样式，以体现文件上传进度的变化
        $percent = $li.find('.progress span');

    // 通过css方法设置找到的进度条元素（$percent）的宽度样式属性，将传入的上传进度百分比（percentage）乘以100并拼接上 '%' 符号后设置为宽度值，这样进度条的宽度就会根据文件上传进度按比例进行变化，直观地展示给用户文件当前的上传进度情况
    $percent.css('width', percentage * 100 + '%');
    // 将当前文件在percentages对象（用于记录每个文件的大小和进度信息的对象）中对应的进度值（数组中的第二个元素）更新为传入的当前上传进度百分比（percentage），确保记录的文件进度信息是最新的，方便后续计算总体上传进度等操作使用
    percentages[ file.id ][ 1 ] = percentage;
    // 调用updateTotalProgress函数（之前定义的用于更新文件上传的总体进度信息以及相关界面显示的函数），在单个文件上传进度更新后，及时更新整体的上传进度情况以及相应的界面展示（比如总体进度条的显示等），保证展示给用户的上传进度信息是准确且实时更新的
    updateTotalProgress();
});

// 为uploader对象（WebUploader实例）绑定'uploadSuccess'事件处理函数，当某个文件上传成功后会触发该函数，传入上传成功的文件对象（file）以及服务器端返回的响应数据（ret，包含了服务器端返回的关于该文件上传结果等相关信息）作为参数，用于根据服务器端返回的结果进行相应的界面提示、数据记录等操作
uploader.on('uploadSuccess', function (file, ret) {
    // 通过文件的id找到对应的 <li> 元素（也就是该文件在页面上对应的整个展示元素），赋值给变量$file，方便后续操作该元素进行相应的界面更新操作等
    var $file = $('#' + file.id);
    try {
        // 尝试获取服务器端返回的响应数据中的原始数据（ret._raw，如果存在的话），如果不存在则直接使用整个响应数据（ret），将获取到的数据赋值给responseText变量，用于后续解析操作
        var responseText = (ret._raw || ret),
            // 通过调用utils对象的str2json函数（应该是用于将字符串转换为JSON对象的自定义函数），将前面获取到的响应数据文本（responseText）转换为JSON对象，赋值给json变量，方便后续根据JSON对象中的具体属性来判断上传结果等情况
            json = utils.str2json(responseText);
        // 判断转换后的JSON对象（json）中的'state'属性值是否为'SUCCESS'，也就是判断服务器端返回的结果表示文件上传是否成功
        if (json.state == 'SUCCESS') {
            // 如果文件上传成功，将服务器端返回的JSON对象（json，包含了文件相关的详细信息等）添加到当前实例对象（_this）的fileList属性（用于记录上传成功的文件相关信息的数组）中，方便后续对上传成功的文件数据进行统一管理和使用
            _this.fileList.push(json);
            // 在找到的文件对应的 <li> 元素（$file）内部添加一个类名为'success'的 <span> 元素，可能用于在页面上展示一个表示文件上传成功的标识（比如一个成功图标之类的元素），给用户一个直观的提示，告知该文件已成功上传
            $file.append('<span class="success"></span>');
        } else {
            // 如果服务器端返回的结果表示文件上传不成功（json.state不是'SUCCESS'），通过jQuery选择器在找到的文件对应的 <li> 元素（$file）中查找类名为'error'的元素（可能是用于展示文件错误信息的元素），调用text方法将JSON对象（json）中的'state'属性值（也就是服务器端返回的错误提示等相关信息）设置为该元素的文本内容，然后调用show方法使其显示出来，在页面上展示出文件上传失败的具体错误信息，告知用户该文件上传出现问题了
            $file.find('.error').text(json.state).show();
        }
    } catch (e) {
        // 如果在尝试解析服务器端返回的响应数据或者进行其他相关操作时出现了异常（比如数据格式不符合预期等情况导致转换JSON对象失败等），通过jQuery选择器在找到的文件对应的 <li> 元素（$file）中查找类名为'error'的元素，调用text方法将预先定义好的表示服务器端上传错误的国际化文本变量lang.errorServerUpload设置为该元素的文本内容，然后调用show方法使其显示出来，在页面上展示出一个通用的服务器端上传错误提示信息，告知用户文件上传出现问题了，但具体原因由于解析异常无法准确展示
        $file.find('.error').text(lang.errorServerUpload).show();
    }
});

// 为uploader对象（WebUploader实例）绑定'uploadError'事件处理函数，当某个文件上传出现错误时会触发该函数，传入出现错误的文件对象（file）以及错误代码（code，可能是WebUploader内部定义的用于标识不同类型错误的代码）作为参数，不过此处函数体为空，可能后续需要根据具体的错误情况添加相应的处理逻辑，比如提示用户具体错误原因、进行重试等操作
uploader.on('uploadError', function (file, code) {
});

// 为uploader对象（WebUploader实例）绑定'error'事件处理函数，当出现全局的上传相关错误时会触发该函数，传入错误代码（code，标识错误类型）以及可能涉及的文件对象（file）作为参数，用于处理一些全局性质的上传错误情况
uploader.on('error', function (code, file) {
    // 判断错误代码（code）是否是'Q_TYPE_DENIED'（可能表示文件类型被拒绝，也就是上传的文件类型不符合要求）或者'F_EXCEED_SIZE'（可能表示文件大小超出限制）这两种情况之一
    if (code == 'Q_TYPE_DENIED' || code == 'F_EXCEED_SIZE') {
        // 如果是文件类型不符合要求或者文件大小超出限制这两种错误情况之一，调用addFile函数（之前定义的用于创建与文件对应的视图展示元素等操作的函数），传入出现错误的文件对象（file），重新创建该文件对应的展示元素，可能用于在页面上再次展示该文件以及对应的错误提示信息等情况，让用户能清楚看到是哪个文件出现了什么类型的错误
        addFile(file);
    }
});

// 为uploader对象（WebUploader实例）绑定'uploadComplete'事件处理函数，当某个文件完成了整个上传流程（无论成功还是失败）后会触发该函数，传入完成上传流程的文件对象（file）以及服务器端返回的响应数据（ret）作为参数，不过此处函数体为空，可能后续需要根据具体业务需求添加相应的处理逻辑，比如进行一些清理操作、记录最终结果等情况
uploader.on('uploadComplete', function (file, ret) {
});

           // 为上传按钮（$upload）绑定点击（click）事件处理函数，当用户点击上传按钮时会触发该函数，用于根据当前文件上传的状态来执行相应的操作，比如开始上传、暂停上传等操作
$upload.on('click', function () {
    // 判断上传按钮（$(this)，在事件处理函数中this指向被点击的按钮元素，通过jQuery包装后进行判断）是否包含类名'disabled'，如果包含该类名，表示按钮当前处于不可用状态（例如上传队列中没有文件时设置的不可点击状态等情况）
    if ($(this).hasClass('disabled')) {
        // 如果按钮处于不可用状态，直接返回false，阻止后续默认的点击事件行为（比如阻止按钮的表单提交等默认行为，在这里就是不让用户进行无效的点击操作）
        return false;
    }

    // 判断当前文件上传状态（state）是否为'ready'，即是否处于可以开始上传的状态
    if (state === 'ready') {
        // 如果是'ready'状态，调用uploader对象（WebUploader实例）的upload方法，触发文件上传操作，开始将上传队列中的文件发送到服务器端进行上传
        uploader.upload();
    } else if (state === 'paused') {
        // 判断当前文件上传状态是否为'paused'，即是否处于暂停上传的状态
        // 如果是'paused'状态，同样调用uploader对象的upload方法，用于在暂停后继续进行文件上传操作，恢复文件的上传流程
        uploader.upload();
    } else if (state === 'uploading') {
        // 判断当前文件上传状态是否为'uploading'，即是否处于正在上传文件的状态
        // 如果是'uploading'状态，调用uploader对象的uploader.stop方法，用于暂停正在进行的文件上传操作，停止向服务器发送文件数据等上传行为
        uploader.stop();
    }
});

// 为上传按钮（$upload）添加表示当前文件上传状态（state）的类名（格式为'state-' + state），通过添加这个类名可以应用相应的样式（例如按钮的外观、可操作性等样式变化）来体现当前文件上传所处的状态情况
$upload.addClass('state-' + state);
// 调用updateTotalProgress函数（之前定义的用于更新文件上传的总体进度信息以及相关界面显示的函数），在按钮相关操作完成后（比如点击按钮开始、暂停上传等操作后），及时更新整体的上传进度情况以及相应的界面展示，保证展示给用户的上传进度信息是准确的
updateTotalProgress();
},
// 定义一个名为getQueueCount的函数，用于获取当前处于可上传状态（比如已添加到队列中等待上传、正在上传、上传进度中这些状态的文件都算可上传状态的文件）的文件数量，是当前实例对象的一个方法
getQueueCount: function () {
    // 初始化几个变量，file用于在循环中临时存储每个文件对象，i作为循环计数器，status用于存储文件的状态，readyFile用于统计处于可上传状态的文件数量，初始值设为0，files通过调用this.uploader（当前实例对应的WebUploader实例）的getFiles方法获取所有已添加到WebUploader实例中的文件对象列表，用于后续遍历判断文件状态
    var file, i, status, readyFile = 0, files = this.uploader.getFiles();
    // 使用一个特殊的for循环语法（在循环条件中进行赋值操作），从files列表中依次取出每个文件对象赋值给file变量，并同时递增循环计数器i，只要file变量能获取到有效的文件对象（也就是files列表还没遍历完）就会继续循环
    for (i = 0; file = files[i++]; ) {
        // 获取当前文件（file）的状态，通过调用file对象的getStatus方法获取，将获取到的状态赋值给status变量，用于后续判断该文件是否处于可上传状态
        status = file.getStatus();
        // 判断文件的状态（status）是否是'queued'（已添加到队列中等待上传）、'uploading'（正在上传）或者'progress'（上传进度中）这几种可上传相关的状态之一，如果是，则将统计可上传状态文件数量的变量（readyFile）加1
        if (status == 'queued' || status == 'uploading' || status == 'progress') readyFile++;
    }
    // 返回统计得到的处于可上传状态的文件数量（readyFile），以便其他地方可以获取并根据这个数量进行相应的操作（比如判断是否有文件可上传来决定上传按钮是否可用等情况）
    return readyFile;
},
// 定义一个名为getInsertList的函数，用于获取要插入的文件列表信息（可能是用于后续在某个编辑器或者其他地方插入文件相关的链接、标题等信息），是当前实例对象的一个方法
getInsertList: function () {
    // 初始化几个变量，i作为循环计数器，link用于存储文件的链接地址，data用于临时存储每个文件相关的数据对象，list用于存储最终要返回的文件列表信息，初始化为一个空数组，prefix通过调用editor对象的getOpt方法获取'fileUrlPrefix'配置项的值（可能是文件链接的前缀地址，用于拼接完整的文件访问地址）
    var i, link, data, list = [],
        prefix = editor.getOpt('fileUrlPrefix');
    // 使用for循环遍历当前实例对象（this）的fileList属性（用于记录上传成功的文件相关信息的数组），循环从0开始，每次递增1，直到遍历完所有元素
    for (i = 0; i < this.fileList.length; i++) {
        // 获取当前索引位置对应的文件相关数据对象，赋值给data变量，方便后续提取文件的相关信息（如链接、标题等）
        data = this.fileList[i];
        // 获取文件相关数据对象（data）中的文件链接地址（url属性），赋值给link变量，用于后续构建要插入的文件信息中的链接部分
        link = data.url;
        // 将一个包含文件标题和链接的对象添加到list数组中，文件标题优先取data.original属性（可能是文件原始名称之类的更合适的标题信息），如果不存在则取文件链接地址（link）中以'/'分割后的最后一部分（也就是文件名部分）作为标题，文件链接则通过将获取到的前缀（prefix）和文件链接地址（link）进行拼接得到完整的可访问地址，这样构建好的对象就包含了要插入的文件的标题和完整链接信息
        list.push({
            title: data.original || link.substr(link.lastIndexOf('/') + 1),
            url: prefix + link
        });
    }
    // 返回构建好的包含要插入的文件标题和链接信息的列表（list），以便其他地方（比如编辑器相关的插入文件操作处）可以获取并使用这些信息进行相应的文件插入操作
    return list;
}
};


/* 在线附件 */
// 定义一个名为OnlineFile的构造函数，用于创建与在线文件相关的对象实例，接收一个参数target，用于指定相关的DOM元素或者元素的标识等信息，该函数是创建在线文件相关功能的入口
function OnlineFile(target) {
    // 判断传入的target参数是否为字符串类型，如果是字符串类型，则通过document.getElementById方法根据该字符串（当作元素的id）获取对应的DOM元素，否则直接将传入的参数当作已经获取到的DOM元素进行赋值，最终将获取到的元素赋值给this.container属性，用于后续操作中代表与在线文件相关的容器元素
    this.container = utils.isString(target)? document.getElementById(target) : target;
    // 调用init方法，用于进行一些初始化操作，比如初始化容器、事件绑定、数据初始化等相关设置，启动在线文件相关功能的初始化流程
    this.init();
}
// 为OnlineFile构造函数的原型对象添加属性和方法，这样通过该构造函数创建的所有实例对象都可以共享这些属性和方法，实现在线文件相关功能的具体逻辑定义
OnlineFile.prototype = {
    // 定义init方法，作为在线文件相关功能初始化的总入口，会依次调用其他几个初始化子函数，完成诸如容器初始化、事件绑定、初始数据准备等各项初始化操作
    init: function () {
        // 调用initContainer方法，用于初始化与在线文件相关的容器元素，比如创建文件列表展示的DOM结构等操作
        this.initContainer();
        // 调用initEvents方法，用于初始化与在线文件相关的事件处理逻辑，比如滚动事件等，方便用户在操作在线文件时有相应的交互效果
        this.initEvents();
        // 调用initData方法，用于初始化在线文件相关的数据，可能是加载初始的文件列表数据等操作，具体根据业务需求而定
        this.initData();
    },
    /* 初始化容器 */
    initContainer: function () {
        // 将this.container（代表与在线文件相关的容器元素）的innerHTML属性设置为空字符串，也就是清空该容器元素内部原有的所有内容，用于重新构建与在线文件展示相关的DOM结构
        this.container.innerHTML = '';
        // 创建一个 <ul> 元素，用于作为在线文件列表的外层容器元素，将其赋值给this.list属性，方便后续向其中添加具体的文件列表项等操作
        this.list = document.createElement('ul');
        // 创建一个 <li> 元素，用于可能的清除浮动等样式相关操作（比如在一些布局中通过添加这个元素来确保父元素能正确撑开高度等情况），将其赋值给this.clearFloat属性，后续会将其添加到文件列表中用于布局相关目的
        this.clearFloat = document.createElement('li');

        // 使用domUtils对象的addClass方法（可能是自定义的添加类名函数）为创建的文件列表元素（this.list）添加类名'list'，用于通过CSS样式来设置文件列表的外观、布局等样式效果
        domUtils.addClass(this.list, 'list');
        // 使用domUtils对象的addClass方法为创建的用于清除浮动的元素（this.clearFloat）添加类名'clearFloat'，同样是为了通过CSS样式来实现相应的布局效果（比如清除浮动相关的样式规则应用到这个元素上）
        domUtils.addClass(this.clearFloat, 'clearFloat');

        // 将用于清除浮动的元素（this.clearFloat）添加到文件列表元素（this.list）中，使其成为文件列表的子元素，符合相应的布局结构要求
        this.list.appendChild(this.clearFloat);
        // 将包含了清除浮动元素的文件列表元素（this.list）添加到与在线文件相关的容器元素（this.container）中，完成在线文件列表展示的基本DOM结构搭建，后续可以向文件列表中添加具体的文件项等内容
        this.container.appendChild(this.list);
    },
    /* 初始化滚动事件,滚动到地步自动拉取数据 */
    initEvents: function () {
        // 将当前实例对象（this）赋值给变量_this，用于在后续一些闭包环境中能正确访问到当前实例对象的属性和方法，避免this指向问题导致的错误
        var _this = this;

        /* 滚动拉取图片 */
        // 使用domUtils对象的on方法（可能是自定义的事件绑定函数）为id为'fileList'的元素（可能就是前面初始化的文件列表所在元素或者相关的滚动容器元素）绑定滚动（scroll）事件处理函数，当该元素发生滚动时会触发此函数，传入事件对象（e）作为参数
        domUtils.on($G('fileList'), 'scroll', function(e){
            // 将触发滚动事件的元素（this，在事件处理函数中this指向触发事件的DOM元素，也就是绑定了滚动事件的那个元素）赋值给变量panel，方便后续操作该元素获取相关的滚动属性等信息
            var panel = this;
            // 判断文件列表容器元素（panel）的滚动高度（scrollHeight，表示整个可滚动内容的高度）减去（元素的可视高度（offsetHeight）加上已经滚动的距离（scrollTop））是否小于10像素，也就是判断是否滚动到了容器元素的底部附近（这里设定10像素的差值作为接近底部的判断条件）
            if (panel.scrollHeight - (panel.offsetHeight + panel.scrollTop) < 10) {
                // 如果滚动到了容器底部附近，调用当前实例对象（_this）的getFileData方法（应该是用于获取更多在线文件数据的函数，虽然此处未展示其具体代码，但从函数名推测其功能），实现自动拉取更多在线文件数据的功能，以满足用户滚动查看更多文件的需求
                _this.getFileData();
            }
        });
          /* 选中图片 */
// 使用domUtils对象的on方法（可能是自定义的事件绑定函数）为当前实例对象（this）的list属性所代表的元素（应该是在线文件列表的DOM元素）绑定点击（click）事件处理函数，当用户点击文件列表中的元素时会触发该函数，传入事件对象（e）作为参数，用于处理图片选中相关的交互逻辑
domUtils.on(this.list, 'click', function (e) {
    // 获取触发点击事件的实际目标元素，兼容不同浏览器获取方式（e.target适用于标准浏览器，e.srcElement适用于IE浏览器），将其赋值给变量target，方便后续操作判断点击的具体元素是什么
    var target = e.target || e.srcElement,
        // 获取目标元素（target）的父节点元素（也就是所在的 <li> 元素，假设文件列表中的每个文件项是用 <li> 元素包裹的），赋值给变量li，用于后续判断是否点击的是文件列表项元素以及进行相应的选中样式处理等操作
        li = target.parentNode;

    // 判断获取到的父节点元素（li）的标签名（tagName）转换为小写形式后是否等于'li'，也就是确认点击的目标元素的父元素确实是文件列表中的 <li> 元素（用于排除点击到其他不符合要求的元素的情况）
    if (li.tagName.toLowerCase() == 'li') {
        // 判断该 <li> 元素（li）是否已经包含类名'selected'（可能表示该文件项已被选中的样式类名），如果包含
        if (domUtils.hasClass(li, 'selected')) {
            // 使用domUtils对象的removeClasses方法（可能是自定义的移除类名函数）从该 <li> 元素（li）中移除'selected'类名，也就是取消该文件项的选中状态，对应的样式效果（比如选中时的背景色等样式）会消失
            domUtils.removeClasses(li, 'selected');
        } else {
            // 如果该 <li> 元素（li）不包含'selected'类名，也就是当前未被选中，使用domUtils对象的addClass方法（可能是自定义的添加类名函数）为该 <li> 元素（li）添加'selected'类名，使其变为选中状态，显示出相应的选中样式效果
            domUtils.addClass(li, 'selected');
        }
    }
});
},
/* 初始化第一次的数据 */
initData: function () {
    // 以下是拉取数据需要使用到的几个变量的初始化，用于记录在线文件数据拉取相关的状态、数量、索引等信息

    /* 拉取数据需要使用的值 */
    // 初始化一个变量state，用于记录当前数据拉取的状态，初始值设为0，具体含义可能根据业务逻辑确定，比如0表示初始状态，后续可能根据不同阶段有不同的值来表示不同的数据拉取情况等
    this.state = 0;
    // 通过调用editor对象的getOpt方法获取'fileManagerListSize'配置项的值（可能表示每次拉取在线文件列表数据的数量大小限制），并赋值给this.listSize变量，用于确定每次向后台请求获取的文件数量
    this.listSize = editor.getOpt('fileManagerListSize');
    // 初始化一个变量this.listIndex，用于记录当前已经拉取的数据在整个数据集中的索引位置，初始值设为0，表示从最开始的位置开始拉取数据，后续会根据实际拉取情况进行更新
    this.listIndex = 0;
    // 初始化一个变量this.listEnd，用于标记是否已经拉取到了所有的在线文件数据，初始值设为false，表示还未拉取完所有数据，当拉取完所有数据后会将其设置为true
    this.listEnd = false;

    /* 第一次拉取数据 */
    // 调用this.getFileData方法（用于向后台拉取图片列表数据的函数），开始进行第一次在线文件数据的拉取操作，获取初始的文件列表数据并展示在页面上，后续根据滚动等操作可能会继续拉取更多数据
    this.getFileData();
},
/* 向后台拉取图片列表数据 */
getFileData: function () {
    // 将当前实例对象（this）赋值给变量_this，用于在后续一些闭包环境中能正确访问到当前实例对象的属性和方法，避免this指向问题导致的错误
    var _this = this;

    // 判断当前是否还未拉取完所有数据（_this.listEnd为false）并且当前是否不在加载数据的过程中（!this.isLoadingData，isLoadingData变量可能用于标记是否正在进行数据请求加载操作），只有这两个条件都满足时才执行后续的数据拉取操作，避免重复请求或者在数据还未加载完时又发起新请求等情况
    if (!_this.listEnd &&!this.isLoadingData) {
        // 如果满足条件，将表示正在加载数据的变量（this.isLoadingData）设置为true，标记当前开始进入数据加载状态，防止其他地方同时触发数据拉取操作
        this.isLoadingData = true;
        // 使用ajax对象（可能是自定义的用于发送异步请求的对象或者基于某个库的请求对象）的request方法发起一个GET请求，向后台服务器获取在线文件（图片）列表数据，传入请求的URL地址以及一些配置参数对象作为参数
        ajax.request(editor.getActionUrl(editor.getOpt('fileManagerActionName')), {
            // 设置请求的超时时间为100000毫秒（也就是100秒），如果请求在这个时间内没有响应则会触发超时处理逻辑，防止请求长时间无响应导致页面卡顿等问题
            timeout: 100000,
            // 设置请求携带的数据，通过调用utils对象的extend方法（可能是用于合并对象的自定义函数），将一个包含起始索引（start，使用this.listIndex变量的值，表示从哪个位置开始拉取数据）和拉取数量（size，使用this.listSize变量的值，表示每次拉取的数据数量）的对象与通过editor对象的queryCommandValue方法获取'serverparam'命令对应的值（可能是一些自定义的服务器端相关参数）进行合并，最终生成包含完整请求数据参数的对象，作为请求携带的数据发送给服务器端
            data: utils.extend({
                    start: this.listIndex,
                    size: this.listSize
                }, editor.queryCommandValue('serverparam')),
            // 设置请求方法为'get'，表示发起一个GET请求，向服务器端获取数据（而不是POST等其他请求方式）
            method: 'get',
            // 设置请求成功的回调函数，当服务器端成功返回数据时会触发该函数，传入服务器端返回的响应对象（r，包含了响应的各种信息，如响应文本、状态码等）作为参数，用于处理成功获取到的数据情况
            onsuccess: function (r) {
                try {
                    // 尝试将服务器端返回的响应文本（r.responseText）通过eval函数（虽然使用eval函数存在一定安全风险，但在这里可能是用于将服务器端返回的符合JSON格式的字符串转换为JavaScript对象，不过更好的方式是使用JSON.parse等安全的解析方法）转换为JavaScript对象，并赋值给变量json，方便后续根据对象中的属性判断数据情况并进行相应处理
                    var json = eval('(' + r.responseText + ')');
                    // 判断转换后的JavaScript对象（json）中的'state'属性值是否为'SUCCESS'，也就是判断服务器端返回的结果表示此次数据获取是否成功（可能根据服务器端的业务逻辑，返回'SUCCESS'表示正常获取到了文件列表数据等情况）
                    if (json.state == 'SUCCESS') {
                        // 如果数据获取成功，调用当前实例对象（_this）的pushData方法（应该是用于将获取到的数据添加到页面或者相关数据存储中的函数，虽然此处未展示其具体代码，但从函数名推测其功能），传入服务器端返回的数据列表（json.list，应该是包含了多个文件相关信息的数组），将获取到的文件数据进行相应的展示等处理操作
                        _this.pushData(json.list);
                        // 更新当前已经拉取的数据在整个数据集中的索引位置（_this.listIndex），通过将服务器端返回的起始索引（json.start，可能是此次返回数据在整个数据集中的起始位置信息）转换为整数后加上返回的数据列表长度（json.list.length）来计算得到新的索引位置，以便下次拉取数据时能从正确的位置继续获取数据
                        _this.listIndex = parseInt(json.start) + parseInt(json.list.length);
                        // 判断如果更新后的索引位置（_this.listIndex）大于等于服务器端返回的总数据量（json.total，表示整个在线文件数据集的总数），说明已经拉取完了所有数据，将标记是否拉取完所有数据的变量（_this.listEnd）设置为true，表示数据拉取结束了
                        if (_this.listIndex >= json.total) {
                            _this.listEnd = true;
                        }
                        // 将表示正在加载数据的变量（_this.isLoadingData）设置为false，标记当前数据加载操作已完成，允许后续再次发起数据拉取请求（如果满足条件的话）
                        _this.isLoadingData = false;
                    }
                } catch (e) {
                    // 如果在尝试解析服务器端返回的数据或者进行其他相关操作时出现了异常（比如数据格式不符合预期等情况导致转换对象失败等），进行以下异常处理逻辑
                    // 判断服务器端返回的响应文本（r.responseText）中是否包含'ue_separate_ue'字符串，如果包含（可能表示一种特殊的数据格式或者错误情况等，具体根据业务逻辑确定）
                    if (r.responseText.indexOf('ue_separate_ue')!= -1) {
                        // 通过split方法将响应文本（r.responseText）按照自身进行分割（这里的分割逻辑看起来有点奇怪，可能是根据特定的数据格式要求进行处理，也许是想获取其中的某个部分作为数据列表，具体需要结合实际业务来看），将分割后的结果赋值给变量list，作为获取到的数据列表
                        var list = r.responseText.split(r.responseText);
                        // 调用当前实例对象（_this）的pushData方法，传入获取到的数据列表（list），将数据进行相应的展示等处理操作，虽然数据格式可能不符合常规的预期，但按照这种特殊情况进行处理
                        _this.pushData(list);
                        // 将当前已经拉取的数据在整个数据集中的索引位置（_this.listIndex）更新为获取到的数据列表长度（list.length）转换为整数后的数值，因为可能这种特殊格式下无法按照常规方式计算索引，只能简单以数据列表长度来表示位置
                        _this.listIndex = parseInt(list.length);
                        // 将标记是否拉取完所有数据的变量（_this.listEnd）设置为true，表示数据拉取结束了，可能在这种特殊情况下认为已经获取完所有能处理的数据了
                        _this.listEnd = true;
                        // 将表示正在加载数据的变量（_this.isLoadingData）设置为false，标记当前数据加载操作已完成，结束这次特殊情况下的数据处理流程
                        _this.isLoadingData = false;
                    }
                }
            },
            // 设置请求失败的回调函数，当请求出现错误（比如网络问题、服务器端返回错误状态码等情况）时会触发该函数，用于处理请求失败的情况，在这里只是简单地将表示正在加载数据的变量（_this.isLoadingData）设置为false，标记当前数据加载操作结束（虽然失败了），允许后续再次发起数据拉取请求（如果满足条件的话）
            onerror: function () {
                _this.isLoadingData = false;
            }
        });
    }
},
       /* 添加图片到列表界面上 */
// 定义一个名为pushData的函数，用于将获取到的在线文件（图片）数据添加到列表界面上进行展示，接收一个参数list，代表从服务器端获取到的文件数据列表（通常是包含多个文件相关信息的数组）
pushData: function (list) {
    // 初始化多个变量，i作为循环计数器，item用于创建每个文件对应的DOM元素（<li>元素，代表列表中的一个文件项），img用于创建图片元素（如果文件是图片类型的话），filetype用于存储文件的类型（通过文件链接的扩展名来判断），preview用于创建文件的预览元素（可能是图片元素或者包含文件相关信息的其他元素，根据文件类型不同而不同），icon用于创建一个图标元素（可能用于展示文件的一些标识等），_this用于保存当前实例对象（this）的引用，方便在闭包等场景下正确访问实例的属性和方法，urlPrefix通过调用editor对象的getOpt方法获取'fileManagerUrlPrefix'配置项的值（可能是文件链接的前缀地址，用于拼接完整的可访问文件链接）
    var i, item, img, filetype, preview, icon, _this = this,
        urlPrefix = editor.getOpt('fileManagerUrlPrefix');
    // 使用for循环遍历传入的文件数据列表（list），从索引0开始，每次递增1，直到遍历完所有元素，用于逐个处理每个文件的数据并添加到界面上
    for (i = 0; i < list.length; i++) {
        // 判断当前索引位置的文件数据（list[i]）是否存在并且其是否包含url属性（也就是判断这个文件数据是否有效且有对应的文件链接地址，用于后续操作）
        if (list[i] && list[i].url) {
            // 创建一个 <li> 元素，作为文件列表中的一个文件项元素，用于包裹文件的相关展示元素（如预览图、图标等），并将其赋值给变量item，后续会向这个元素中添加其他子元素来完善文件项的展示内容
            item = document.createElement('li');
            // 创建一个 <span> 元素，可能作为文件相关的图标元素（具体图标样式等可能后续通过类名等方式设置），赋值给变量icon，用于后续添加到文件项元素（item）中
            icon = document.createElement('span');
            // 获取当前文件的类型，通过截取文件链接（list[i].url）中最后一个 '.' 之后的字符串（也就是文件扩展名）来确定文件类型，并赋值给变量filetype，用于后续根据文件类型进行不同的展示处理（比如图片文件和非图片文件展示方式不同）
            filetype = list[i].url.substr(list[i].url.lastIndexOf('.') + 1);

            // 判断文件类型（filetype）是否在常见的图片文件类型列表（"png|jpg|jpeg|gif|bmp"）中，如果在这个列表中，说明是图片文件，进行以下处理逻辑来展示图片预览
            if ("png|jpg|jpeg|gif|bmp".indexOf(filetype)!= -1) {
                // 创建一个 <img> 元素，用于展示图片文件的预览图，赋值给变量preview，后续会设置其相关属性（如src、width等）来正确显示图片
                preview = document.createElement('img');
                // 使用domUtils对象的on方法（可能是自定义的事件绑定函数）为创建的图片元素（preview）绑定加载（load）事件处理函数，当图片加载完成时会触发该函数，传入一个立即执行函数返回的另一个函数作为事件处理函数，这样做是为了在闭包中正确传递当前的图片元素（preview）引用，避免出现变量作用域问题
                domUtils.on(preview, 'load', (function (image) {
                    return function () {
                        // 在图片加载完成的回调函数内部，调用当前实例对象（_this）的scale方法（应该是用于调整图片大小、缩放等操作的函数，虽然此处未展示其具体代码，但从函数名推测其功能），传入当前图片元素（image，也就是传入的参数image，它在闭包中指向最初创建的preview元素）以及图片父元素（image.parentNode，也就是包含这个图片的元素，这里应该是文件项中的用于展示图片的区域元素）的宽度（offsetWidth）和高度（offsetHeight）作为参数，根据父元素的尺寸来对图片进行缩放等适配操作，确保图片在界面上能合适地展示
                        _this.scale(image, image.parentNode.offsetWidth, image.parentNode.offsetHeight);
                    };
                })(preview));
                // 设置图片元素（preview）的宽度为113像素，这里固定了一个初始宽度，后续可能根据缩放等操作再进行调整，具体根据界面布局和展示需求而定
                preview.width = 113;
                // 设置图片元素（preview）的src属性，通过拼接文件链接前缀（urlPrefix）、文件的实际链接地址（list[i].url）以及一个用于避免缓存的参数（根据文件链接中是否已经包含'?'来决定添加'?noCache='或者'&noCache='，并加上当前时间的时间戳转换为36进制后的字符串，这样每次请求图片时由于时间戳不同可以避免浏览器缓存旧的图片，确保获取到最新的图片数据），使得图片能正确加载并显示出来
                preview.setAttribute('src', urlPrefix + list[i].url + (list[i].url.indexOf('?') == -1? '?noCache=' : '&noCache=') + (+new Date()).toString(36));
            } else {
                // 如果文件类型不是常见的图片文件类型，进行以下处理逻辑来展示非图片文件的相关信息
                var ic = document.createElement('i'),
                    textSpan = document.createElement('span');
                // 设置 <span> 元素（textSpan）的innerHTML属性为文件链接（list[i].url）中最后一个 '/' 之后的字符串（也就是文件名部分），用于展示文件的名称信息
                textSpan.innerHTML = list[i].url.substr(list[i].url.lastIndexOf('/') + 1);
                // 创建一个 <div> 元素，作为非图片文件的整体预览元素，将其赋值给变量preview，后续会向这个元素中添加其他子元素（如文件类型图标、文件名等）来展示文件相关信息
                preview = document.createElement('div');
                // 将创建的 <i> 元素（ic，可能用于展示文件类型对应的图标样式等）添加到 <div> 元素（preview）中，作为其子元素
                preview.appendChild(ic);
                // 将创建的 <span> 元素（textSpan，展示文件名）添加到 <div> 元素（preview）中，同样作为其子元素，完成非图片文件预览元素内部的结构搭建
                preview.appendChild(textSpan);
                // 使用domUtils对象的addClass方法（可能是自定义的添加类名函数）为 <div> 元素（preview）添加类名'file-wrapper'，通过CSS样式类来设置这个元素的外观、布局等样式效果，使其符合非图片文件展示的整体样式要求
                domUtils.addClass(preview, 'file-wrapper');
                // 使用domUtils对象的addClass方法为 <span> 元素（textSpan）添加类名'file-title'，用于设置文件名展示的样式效果（比如字体、颜色等样式），使其更清晰地展示文件名
                domUtils.addClass(textSpan, 'file-title');
                // 使用domUtils对象的addClass方法为 <i> 元素（ic）添加类名'file-type-' + filetype，通过动态添加包含文件类型的类名，可以根据不同的文件类型应用不同的图标样式等效果，方便用户直观识别文件类型
                domUtils.addClass(ic, 'file-type-' + filetype);
                // 使用domUtils对象的addClass方法再次为 <i> 元素（ic）添加类名'file-preview'，可能用于统一设置文件预览相关元素的一些通用样式效果等情况
                domUtils.addClass(ic, 'file-preview');
            }
            // 使用domUtils对象的addClass方法为之前创建的 <span> 元素（icon）添加类名'icon'，用于设置这个图标元素的样式（比如图标大小、颜色、位置等样式效果），使其符合在文件项中的展示要求
            domUtils.addClass(icon, 'icon');
            // 为文件项元素（item）设置自定义的'data-url'属性，其值通过拼接文件链接前缀（urlPrefix）和文件的实际链接地址（list[i].url）得到，用于在后续操作中方便获取文件的完整链接信息（例如点击文件项进行相关操作时可能会用到这个链接）
            item.setAttribute('data-url', urlPrefix + list[i].url);
            // 判断当前文件数据（list[i]）中是否包含'original'属性（可能是文件的原始名称等更合适的标题信息），如果包含
            if (list[i].original) {
                // 为文件项元素（item）设置自定义的'data-title'属性，其值为文件的'original'属性值，用于设置文件项更准确的标题信息，方便在界面上展示（比如鼠标悬停提示等场景可以显示这个标题）
                item.setAttribute('data-title', list[i].original);
            }

            // 将创建好的文件预览元素（preview，可能是图片元素或者包含文件相关信息的 <div> 元素，取决于文件类型）添加到文件项元素（item）中，作为其子元素，完成文件项中主要内容的添加
            item.appendChild(preview);
            // 将设置好类名的图标元素（icon）添加到文件项元素（item）中，同样作为其子元素，进一步完善文件项的展示结构
            item.appendChild(icon);
            // 将构建好的文件项元素（item）插入到当前实例对象（this）的list属性所代表的文件列表元素（应该是之前初始化的 <ul> 元素）中，并且插入位置在this.clearFloat元素（可能是用于清除浮动等布局相关的元素）之前，这样新添加的文件项就会按照顺序展示在文件列表中合适的位置上
            this.list.insertBefore(item, this.clearFloat);
        }
    }
},
      /* 改变图片大小 */
// 定义一个名为'scale'的函数，用于根据指定的参数来改变图片的大小以及对图片进行相应的位置调整（例如使其在某个容器内居中显示等情况），接收四个参数，分别是要操作的图片元素（img）、期望的目标宽度（w）、期望的目标高度（h）以及用于指定调整类型的参数（type）
scale: function (img, w, h, type) {
    // 获取传入的图片元素（img）当前的实际宽度值（单位应该是像素），并将其赋值给变量ow，用于后续根据原始宽高比例来计算调整后的宽高尺寸等操作
    var ow = img.width,
        // 获取传入的图片元素（img）当前的实际高度值（单位应该是像素），赋值给变量oh，同样方便后续按照原始宽高比例进行相应的尺寸计算和调整逻辑
        oh = img.height;

    // 判断传入的调整类型参数（type）是否等于'justify'，'justify'可能表示一种特定的图片缩放及对齐方式（比如让图片在某个区域内按比例缩放并居中显示等情况），如果等于该值，则进入以下相应的处理逻辑
    if (type == 'justify') {
        // 判断图片当前的原始宽度（ow）是否大于等于原始高度（oh），如果满足这个条件，说明图片比较“宽”，按照以下方式调整图片的宽高及位置
        if (ow >= oh) {
            // 将图片元素（img）的宽度属性（width）设置为传入的目标宽度值（w），也就是让图片宽度达到期望的宽度尺寸
            img.width = w;
            // 根据图片原始的宽高比例（oh / ow）来计算调整后的高度值，通过目标高度（h）乘以原始宽高比例得到调整后的高度（h * oh / ow），这样能保证图片按比例缩放，然后将计算得到的高度值赋给图片元素（img）的高度属性（height）
            img.height = h * oh / ow;
            // 计算图片在水平方向上需要设置的外边距（marginLeft），目的是让图片在水平方向上居中显示。先计算图片调整后的宽度（img.width）与目标宽度（w）的差值的一半（(img.width - w) / 2），然后取其绝对值并转换为整数（通过parseInt函数），最后在前面添加负号（'-'），将得到的值设置为图片元素（img）的marginLeft样式属性值，这样图片就能在水平方向上相对于父容器居中了
            img.style.marginLeft = '-' + parseInt((img.width - w) / 2) + 'px';
        } else {
            // 如果图片当前的原始宽度（ow）小于原始高度（oh），说明图片比较“高”，则按照以下方式调整图片的宽高及位置
            // 根据图片原始的宽高比例（ow / oh）来计算调整后的宽度值，通过目标宽度（w）乘以原始宽高比例得到调整后的宽度（w * ow / oh），保证图片按比例缩放，然后将该宽度值赋给图片元素（img）的宽度属性（width）
            img.width = w * ow / oh;
            // 将图片元素（img）的高度属性（height）设置为传入的目标高度值（h），使图片高度达到期望的高度尺寸
            img.height = h;
            // 计算图片在垂直方向上需要设置的外边距（marginTop），用于让图片在垂直方向上居中显示。先计算图片调整后的高度（img.height）与目标高度（h）的差值的一半（(img.height - h) / 2），然后取其绝对值并转换为整数（通过parseInt函数），最后在前面添加负号（'-'），将得到的值设置为图片元素（img）的marginTop样式属性值，使图片在垂直方向上相对于父容器居中
            img.style.marginTop = '-' + parseInt((img.height - h) / 2) + 'px';
        }
    } else {
        // 如果传入的调整类型参数（type）不等于'justify'，则进入以下默认的处理逻辑（可能是另一种图片缩放及位置调整方式）
        // 判断图片当前的原始宽度（ow）是否大于等于原始高度（oh），如果满足这个条件，按照以下方式调整图片的宽高及位置
        if (ow >= oh) {
            // 根据图片原始的宽高比例（ow / oh）来计算调整后的宽度值，通过目标宽度（w）乘以原始宽高比例得到调整后的宽度（w * ow / oh），保证图片按比例缩放，然后将该宽度值赋给图片元素（img）的宽度属性（width）
            img.width = w * ow / oh;
            // 将图片元素（img）的高度属性（height）设置为传入的目标高度值（h），使图片高度达到期望的高度尺寸
            img.height = h;
            // 计算图片在水平方向上需要设置的外边距（marginLeft），用于让图片在水平方向上有一定的偏移以达到某种布局效果（具体根据实际需求而定）。先计算图片调整后的宽度（img.width）与目标宽度（w）的差值的一半（(img.width - w) / 2），然后取其绝对值并转换为整数（通过parseInt函数），最后在前面添加负号（'-'），将得到的值设置为图片元素（img）的marginLeft样式属性值
            img.style.marginLeft = '-' + parseInt((img.width - w) / 2) + 'px';
        } else {
            // 如果图片当前的原始宽度（ow）小于原始高度（oh），则按照以下方式调整图片的宽高及位置
            // 将图片元素（img）的宽度属性（width）设置为传入的目标宽度值（w），让图片宽度达到期望的宽度尺寸
            img.width = w;
            // 根据图片原始的宽高比例（oh / ow）来计算调整后的高度值，通过目标高度（h）乘以原始宽高比例得到调整后的高度（h * oh / ow），保证图片按比例缩放，然后将该高度值赋给图片元素（img）的高度属性（height）
            img.height = h * oh / ow;
            // 计算图片在垂直方向上需要设置的外边距（marginTop），用于让图片在垂直方向上有一定的偏移以达到某种布局效果（具体根据实际需求而定）。先计算图片调整后的高度（img.height）与目标高度（h）的差值的一半（(img.height - h) / 2），然后取其绝对值并转换为整数（通过parseInt函数），最后在前面添加负号（'-'），将得到的值设置为图片元素（img）的marginTop样式属性值
            img.style.marginTop = '-' + parseInt((img.height - h) / 2) + 'px';
        }
    }
},
// 定义一个名为'getInsertList'的函数，用于获取当前被选中的文件（图片）对应的列表信息，这些信息可能后续用于插入到其他地方（比如编辑器等场景），函数会遍历文件列表元素中的子元素，筛选出被选中的元素，并提取其相关属性信息组成列表返回
getInsertList: function () {
    // 初始化循环计数器变量i，用于后续遍历文件列表元素的子元素。同时通过this.list.children获取当前实例对象（this）的list属性所代表的文件列表元素（应该是之前创建的 <ul> 元素）的所有子元素（也就是每个文件对应的 <li> 元素等），并赋值给变量lis，方便后续遍历这些子元素来判断哪些是被选中的元素。初始化一个空数组list，用于存储最终提取出来的被选中文件的相关信息（如标题、链接等）
    var i, lis = this.list.children, list = [];
    // 使用for循环遍历获取到的文件列表子元素（lis），从索引0开始，每次递增1，直到遍历完所有子元素，用于逐个检查每个子元素是否被选中，并提取相应的信息
    for (i = 0; i < lis.length; i++) {
        // 使用domUtils对象的hasClass方法（可能是自定义的判断元素是否包含某个类名的函数）来判断当前遍历到的子元素（lis[i]，即每个 <li> 元素等）是否包含'selected'类名，'selected'类名可能表示该文件项在界面上处于被选中的状态，只有被选中的元素才进行以下信息提取操作
        if (domUtils.hasClass(lis[i], 'selected')) {
            // 通过getAttribute方法获取当前被选中的元素（lis[i]）的自定义'data-url'属性值，该属性值应该是对应文件的链接地址，将其赋值给变量url，用于后续构建要返回的文件信息对象中的链接部分
            var url = lis[i].getAttribute('data-url');
            // 通过getAttribute方法获取当前被选中的元素（lis[i]）的自定义'data-title'属性值，该属性值可能是对应文件更合适的标题信息（比如原始文件名等），如果该属性不存在（也就是返回值为假值），则通过截取文件链接（url）中最后一个'/'之后的字符串（也就是文件名部分）作为标题，将最终确定的标题赋值给变量title，用于后续构建要返回的文件信息对象中的标题部分
            var title = lis[i].getAttribute('data-title') || url.substr(url.lastIndexOf('/') + 1);
            // 将一个包含标题（title）和链接（url）信息的对象添加到list数组中，这样就构建好了一个代表被选中文件相关信息的对象，后续可以将整个list数组返回，供其他地方使用这些文件信息进行相应的插入等操作
            list.push({
                title: title,
                url: url
            });
        }
    }
    // 返回包含所有被选中文件相关信息（标题和链接）的列表（list），以便在其他代码中可以获取并根据这些信息进行相应的处理（比如插入到编辑器中的相应位置等操作）
    return list;
}
};


})();