From 9e0bfc0904620b4bf18555a3eb0a93a16717c3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E9=91=AB?= <1614396461@qq.com> Date: Tue, 17 Dec 2024 10:03:48 +0800 Subject: [PATCH] zx --- modules/Logistics.js | 96 ++++--- modules/authorization.js | 123 ++++---- modules/database.js | 138 +++++---- modules/logger.js | 30 +- modules/passport.js | 153 ++++++---- modules/resextra.js | 42 ++- modules/ueditor.js | 142 +++++---- public2/ueditor/dialogs/map/map.html | 270 +++++++++++------- public2/ueditor/dialogs/map/show.html | 57 +++- public2/ueditor/dialogs/music/music.css | 206 +++++++++++-- public2/ueditor/dialogs/music/music.html | 39 ++- public2/ueditor/dialogs/music/music.js | 83 ++++-- public2/ueditor/dialogs/preview/preview.html | 86 +++--- public2/ueditor/dialogs/scrawl/scrawl.css | 226 ++++++++++++--- public2/ueditor/dialogs/scrawl/scrawl.html | 160 ++++++----- public2/ueditor/dialogs/scrawl/scrawl.js | 155 ++++++---- .../dialogs/searchreplace/searchreplace.html | 232 +++++++++------ .../dialogs/searchreplace/searchreplace.js | 159 +++++++---- .../dialogs/snapscreen/snapscreen.html | 170 +++++++---- .../ueditor/dialogs/spechars/spechars.html | 42 ++- public2/ueditor/dialogs/spechars/spechars.js | 38 ++- public2/ueditor/dialogs/table/edittable.css | 77 ++++- public2/ueditor/dialogs/table/edittable.html | 136 +++++---- public2/ueditor/dialogs/table/edittable.js | 75 ++++- public2/ueditor/dialogs/table/edittd.html | 104 ++++--- public2/ueditor/dialogs/table/edittip.html | 48 +++- public2/ueditor/dialogs/template/config.js | 49 ++-- public2/ueditor/dialogs/template/template.css | 160 +++++++++-- .../ueditor/dialogs/template/template.html | 21 +- public2/ueditor/dialogs/template/template.js | 63 ++-- public2/ueditor/dialogs/video/video.css | 87 +++++- public2/ueditor/dialogs/video/video.html | 170 ++++++----- public2/ueditor/dialogs/video/video.js | 64 +++-- public2/ueditor/dialogs/webapp/webapp.html | 82 ++++-- .../ueditor/dialogs/wordimage/wordimage.html | 181 +++++++++--- .../ueditor/dialogs/wordimage/wordimage.js | 130 +++++---- 36 files changed, 2854 insertions(+), 1240 deletions(-) diff --git a/modules/Logistics.js b/modules/Logistics.js index 5fb82e3..534bb6e 100644 --- a/modules/Logistics.js +++ b/modules/Logistics.js @@ -1,54 +1,68 @@ -// 导入 request 模块 -const request = require('request') +// 导入 request 模块,该模块常用于在 Node.js 中发起 HTTP 请求,方便与其他网络服务进行交互 +const request = require('request'); // 自动匹配运单号所属的物流公司 function autoComNumber(orderno) { - const url = `https://www.kuaidi100.com/autonumber/autoComNum?resultv2=1&text=${orderno}` - return new Promise(function(resolve, reject) { - request(url, (err, response, body) => { - if (err) return reject({ status: 500, msg: err.message }) - // resolve(body) - // console.log(body.num) - body = JSON.parse(body) - if (body.auto.length <= 0) return reject({ status: 501, msg: '无对应的物流公司' }) - resolve({ status: 200, msg: body.auto[0], comCode: body.auto[0].comCode }) - }) - }) + // 构造请求的 URL,向快递100的接口发送请求,尝试自动匹配运单号对应的物流公司 + // 将运单号拼接到 URL 参数中,resultv2=1 可能是用于指定返回结果的某种格式或版本相关参数 + const url = `https://www.kuaidi100.com/autonumber/autoComNum?resultv2=1&text=${orderno}`; + // 返回一个 Promise 对象,用于处理异步操作,使得外部可以使用 async/await 语法来等待该函数执行完成 + return new Promise(function (resolve, reject) { + // 使用 request 模块发起 GET 请求,传入 URL 和回调函数,回调函数接收请求过程中的错误、响应对象以及响应体内容作为参数 + request(url, (err, response, body) => { + // 如果请求过程中出现错误,调用 reject 函数拒绝这个 Promise,并返回包含状态码 500 和错误信息的对象 + if (err) return reject({ status: 500, msg: err.message }); + // 将响应体内容(通常是 JSON 字符串格式)解析为 JavaScript 对象,方便后续提取数据 + body = JSON.parse(body); + // 如果解析后的 body.auto 数组长度小于等于 0,意味着没有匹配到对应的物流公司,同样调用 reject 函数拒绝 Promise,并返回相应的错误信息对象 + if (body.auto.length <= 0) return reject({ status: 501, msg: '无对应的物流公司' }); + // 如果匹配到了物流公司,调用 resolve 函数成功解决这个 Promise,返回包含状态码 200、物流公司信息以及对应的公司编码的对象 + resolve({ status: 200, msg: body.auto[0], comCode: body.auto[0].comCode }); + }); + }); } +// 定义一个异步函数,用于获取物流信息,接收 Express 框架的请求(req)和响应(res)对象作为参数(从函数名和使用方式推测可能在 Express 应用中使用) async function getLogisticsInfo(req, res) { - const result = await autoComNumber(req.params.orderno) + // 调用 autoComNumber 函数,传入请求参数中的运单号(req.params.orderno),并使用 await 等待该异步操作完成,获取匹配物流公司后的结果 + const result = await autoComNumber(req.params.orderno); - if (result.status !== 200) { - return { - meta: { - status: 500, - message: '获取物流信息失败!' - } + // 如果返回结果的状态码不是 200,说明匹配物流公司出现问题,直接返回一个包含错误状态和相应错误消息的对象给客户端 + if (result.status!== 200) { + return { + meta: { + status: 500, + message: '获取物流信息失败!' + } + }; } - } - const dataUrl = `https://www.kuaidi100.com/query?type=${result.comCode}&postid=${req.params.orderno}&temp=0.2595247267684455` - request(dataUrl, (err, response, body) => { - if (err) { - return res.send({ - meta: { - status: 501, - message: '获取物流信息失败!' + // 根据匹配到的物流公司编码和运单号构造查询物流信息的 URL,向快递100的另一个接口发送请求以获取详细物流信息 + const dataUrl = `https://www.kuaidi100.com/query?type=${result.comCode}&postid=${req.params.orderno}&temp=0.2595247267684455`; + // 使用 request 模块发起请求,传入构造好的 URL 和回调函数,处理获取物流信息过程中的各种情况 + request(dataUrl, (err, response, body) => { + // 如果请求过程中出现错误,使用 Express 的 res.send 方法向客户端发送包含错误状态和相应错误消息的对象,表示获取物流信息失败 + if (err) { + return res.send({ + meta: { + status: 501, + message: '获取物流信息失败!' + } + }); } - }) - } - // 获取物流信息成功 - return res.send({ - meta: { - status: 200, - message: '获取物流信息成功!' - }, - data: (JSON.parse(body)).data - }) - }) + // 如果请求成功,解析响应体内容(假设为 JSON 格式),提取其中的物流信息数据(.data 属性,具体格式取决于快递100接口返回的数据结构), + // 然后使用 Express 的 res.send 方法向客户端发送包含成功状态、相应消息以及物流信息数据的对象,表示获取物流信息成功 + return res.send({ + meta: { + status: 200, + message: '获取物流信息成功!' + }, + data: (JSON.parse(body)).data + }); + }); } +// 将 getLogisticsInfo 函数作为模块的属性导出,方便其他模块引入并使用这个函数来获取物流信息 module.exports = { - getLogisticsInfo -} + getLogisticsInfo +}; \ No newline at end of file diff --git a/modules/authorization.js b/modules/authorization.js index 7142ec4..82ada1f 100644 --- a/modules/authorization.js +++ b/modules/authorization.js @@ -1,74 +1,91 @@ +// 引入Node.js的path模块,用于处理文件路径相关操作 var path = require('path'); +// 原本要引入的roles控制器模块,此处被注释掉了,可能后续会按需启用 // var roles_controller = require("../controllers/roles"); +// 再次引入path模块,前面的引入语句重复了,但在Node.js中不会有实质影响,可考虑优化掉重复引入的情况 var path = require("path"); +// 创建一个全局对象service_caches,用于缓存服务相关的模块或数据,初始为空对象 global.service_caches = {}; -// 存储全局验证函数 +// 创建一个全局变量service_auth_fn,用于存储全局验证函数,初始值为null global.service_auth_fn = null; /** - * 构造回调对象格式 + * Invocation函数用于构造一个回调对象格式,主要用于在调用服务的具体方法时进行权限验证等相关操作。 * - * @param {[type]} serviceName 服务名称 - * @param {[type]} actionName 动作名称(方法名) - * @param {[type]} serviceModule 服务模块 - * @param {[type]} origFunc 原始方法 + * @param {[type]} serviceName 服务名称,用于标识具体是哪个服务。 + * @param {[type]} actionName 动作名称(方法名),对应服务模块里具体的函数名称。 + * @param {[type]} serviceModule 服务模块,即通过require加载进来的包含具体业务逻辑函数的模块对象。 + * @param {[type]} origFunc 原始方法,也就是服务模块里未经包装的原始业务逻辑函数。 */ -function Invocation(serviceName,actionName,serviceModule,origFunc) { - return function() { - var origArguments = arguments; - return function(req,res,next) { - if(global.service_auth_fn) { - global.service_auth_fn(req,res,next,serviceName,actionName,function(pass) { - if(pass) { - origFunc.apply(serviceModule,origArguments); - } else { - res.sendResult(null,401,"权限验证失败"); - } - }); - } else { - res.sendResult(null,401,"权限验证失败"); - } - } - } +function Invocation(serviceName, actionName, serviceModule, origFunc) { + // 返回一个新的函数,这个函数会接收一些参数(此处未在形参中体现,在调用时会传入),并返回另一个函数作为真正的回调函数 + return function () { + var origArguments = arguments; + return function (req, res, next) { + // 判断全局验证函数是否存在,如果存在则进行权限验证流程 + if (global.service_auth_fn) { + global.service_auth_fn(req, res, next, serviceName, actionName, function (pass) { + // 如果权限验证通过(pass为true),则执行原始的业务逻辑函数 + if (pass) { + origFunc.apply(serviceModule, origArguments); + } else { + // 如果权限验证失败,向客户端返回相应的错误信息,状态码为401表示未授权 + res.sendResult(null, 401, "权限验证失败"); + } + }); + } else { + // 如果全局验证函数不存在,直接返回权限验证失败的错误信息给客户端 + res.sendResult(null, 401, "权限验证失败"); + } + } + } } -// 获取服务对象 -module.exports.getService = function(serviceName) { +// 定义一个函数用于获取服务对象,它是模块对外暴露的接口之一 +module.exports.getService = function (serviceName) { + // 先检查全局缓存中是否已经存在指定名称的服务对象,如果存在则直接返回缓存中的服务对象 + if (global.service_caches[serviceName]) { + return global.service_caches[serviceName]; + } - if(global.service_caches[serviceName]) { - return global.service_caches[serviceName]; - } + // 构建服务模块的文件路径,通过拼接当前工作目录、"services"文件夹以及服务名称来确定具体路径 + var servicePath = path.join(process.cwd(), "services", serviceName); - var servicePath = path.join(process.cwd(),"services",serviceName); - - var serviceModule = require(servicePath); - if(!serviceModule) { - console.log("模块没有被发现"); - return null; - } - global.service_caches[serviceName] = {}; + // 通过require加载对应的服务模块,如果模块不存在则返回null并在控制台打印提示信息 + var serviceModule = require(servicePath); + if (!serviceModule) { + console.log("模块没有被发现"); + return null; + } - console.log("*****************************************"); - console.log("拦截服务 => %s",serviceName); - console.log("*****************************************"); - for(actionName in serviceModule) { + // 在全局缓存对象中为当前服务名称创建一个空对象,用于后续存储该服务的具体方法相关的回调对象等信息 + global.service_caches[serviceName] = {}; - if(serviceModule && serviceModule[actionName] && typeof(serviceModule[actionName]) == "function") { - var origFunc = serviceModule[actionName]; - global.service_caches[serviceName][actionName] = Invocation(serviceName,actionName,serviceModule,origFunc); - console.log("action => %s",actionName); - } - } - // console.log(global.service_caches); - console.log("*****************************************\n"); - return global.service_caches[serviceName]; -} + // 打印一些提示信息,表明正在拦截指定名称的服务,方便调试和查看流程 + console.log("*****************************************"); + console.log("拦截服务 => %s", serviceName); + console.log("*****************************************"); -// 设置全局验证函数 -module.exports.setAuthFn = function(authFn) { - global.service_auth_fn = authFn; + // 遍历服务模块里的所有属性(通常是方法) + for (actionName in serviceModule) { + // 检查属性对应的是否是一个函数(即服务模块里有效的业务逻辑函数) + if (serviceModule && serviceModule[actionName] && typeof (serviceModule[actionName]) == "function") { + var origFunc = serviceModule[actionName]; + // 使用Invocation函数构造该方法对应的回调对象,并将其存储到全局缓存对象中对应的服务和方法名下 + global.service_caches[serviceName][actionName] = Invocation(serviceName, actionName, serviceModule, origFunc); + console.log("action => %s", actionName); + } + } + // 打印一些分割线和空行,用于在控制台输出中更清晰地区分不同服务的处理情况,此处注释掉了打印全局缓存对象的语句 + // console.log(global.service_caches); + console.log("*****************************************\n"); + return global.service_caches[serviceName]; } +// 定义一个函数用于设置全局验证函数,它也是模块对外暴露的接口,供外部传入具体的验证函数 +module.exports.setAuthFn = function (authFn) { + global.service_auth_fn = authFn; +} \ No newline at end of file diff --git a/modules/database.js b/modules/database.js index 7fd8a20..32988e9 100644 --- a/modules/database.js +++ b/modules/database.js @@ -1,77 +1,95 @@ +// 引入Node.js的mysql模块,用于与MySQL数据库进行交互(虽然此处只是引入,后续具体使用情况暂未明确体现) require('mysql'); +// 引入Node.js的文件系统模块fs,用于对文件进行读写等操作 var fs = require("fs"); +// 引入orm模块,可能用于对象关系映射(Object Relational Mapping)相关操作,方便在Node.js中操作数据库 var orm = require("orm"); +// 引入bluebird模块,用于提供更强大的Promise功能,便于处理异步操作 var Promise = require("bluebird"); +// 引入path模块,用于处理文件路径相关的操作 var path = require("path"); /* - app: 应用程序环境 - config: 数据库配置 - callback: 回调 -*/ -function initialize(app,callback) { + * initialize函数用于初始化数据库相关的配置以及加载ORM(对象关系映射)模型, + * 它接收应用程序环境对象、回调函数作为参数,通过一系列操作完成数据库连接和模型加载, + * 并在操作完成后通过回调函数返回相应结果。 + * + * @param {Object} app - 应用程序环境对象,通常包含了应用的一些全局配置和上下文信息,可用于挂载数据库实例、模型等相关对象。 + * @param {Function} callback - 回调函数,在数据库初始化及模型加载完成(成功或失败)后被调用,用于传递操作结果等信息。 + */ +function initialize(app, callback) { + // 加载配置文件,通过config模块(这里应该是自定义的配置管理模块)获取名为"db_config"的配置信息 + var config = require('config').get("db_config"); - // 加载配置文件 - var config = require('config').get("db_config"); - - // 从配置中获取数据库配置 - var opts = { - protocol : config.get("protocol"), - host : config.get("host"), - database : config.get("database"), - port : config.get("port"), - user : config.get("user"), - password : config.get("password"), - query : {pool: true,debug: true} - }; + // 从配置信息中提取数据库相关的配置参数,构建一个包含协议、主机、数据库名称、端口、用户名、密码以及查询相关配置(启用连接池、开启调试模式)的对象opts + var opts = { + protocol: config.get("protocol"), + host: config.get("host"), + database: config.get("database"), + port: config.get("port"), + user: config.get("user"), + password: config.get("password"), + query: { pool: true, debug: true } + }; - - console.log("数据库连接参数 %s",JSON.stringify(opts)); + // 在控制台打印数据库连接参数,将opts对象转换为JSON字符串格式输出,方便查看配置情况 + console.log("数据库连接参数 %s", JSON.stringify(opts)); - // 初始化ORM模型 - app.use(orm.express(opts, { - define: function (db, models, next) { + // 使用orm模块的express方法初始化ORM模型,将数据库配置参数opts以及一个包含define函数的对象作为参数传入 + app.use(orm.express(opts, { + define: function (db, models, next) { + // 将数据库实例db挂载到应用程序环境对象app上,方便在其他地方访问数据库实例 + app.db = db; + // 同时也将数据库实例挂载到全局对象global上,命名为database,不过使用全局变量需要谨慎,避免命名冲突等问题 + global.database = db; - app.db = db; - global.database = db; + // 获取映射文件的路径,通过拼接当前工作目录和"/models"来确定模型文件所在的文件夹路径 + var modelsPath = path.join(process.cwd(), "/models"); - // 获取映射文件路径 - var modelsPath = path.join(process.cwd(),"/models"); - - // 读取所有模型文件 - fs.readdir(modelsPath,function(err, files) { - // 存放所有的加载模型函数 - var loadModelAsynFns = new Array(); - // console.log("开始加载 ORM 模型层文件 "); - for (var i = 0; i < files.length; i++) { - var modelPath = modelsPath + "/" +files[i]; - // console.log("加载模型 %s",modelPath); - loadModelAsynFns[i] = db.loadAsync(modelPath); - } - - Promise.all(loadModelAsynFns) - .then(function(){ - // console.log("ORM 模型加载完成"); - // 挂载模型集合 + // 使用文件系统模块的readdir方法读取指定路径下的所有文件(即模型文件),读取完成后会调用回调函数处理结果 + fs.readdir(modelsPath, function (err, files) { + // 创建一个数组,用于存放所有加载模型的异步函数,每个元素对应一个模型文件的加载操作 + var loadModelAsynFns = new Array(); + // 以下循环遍历读取到的所有文件,准备加载每个模型文件对应的模型定义(通过db.loadAsync方法异步加载) + // console.log("开始加载 ORM 模型层文件 "); + for (var i = 0; i < files.length; i++) { + var modelPath = modelsPath + "/" + files[i]; + // console.log("加载模型 %s", modelPath); + // 将每个模型文件的异步加载函数存入数组中,后续会统一处理这些异步加载操作 + loadModelAsynFns[i] = db.loadAsync(modelPath); + } - for(var modelName in db.models){ - models[modelName] = db.models[modelName]; - } - app.models = models; - callback(null); - next(); - }) - .catch(function(error){ - console.error('加载模块出错 error: ' + err); - callback(error); - next(); - }); - }); - } - })); + // 使用Promise.all方法来并行处理所有模型文件的加载操作,当所有加载操作都成功完成后,执行then回调函数 + Promise.all(loadModelAsynFns) + .then(function () { + // console.log("ORM 模型加载完成"); + // 遍历数据库实例中已加载的所有模型,将每个模型挂载到models对象上,方便统一管理和访问 + for (var modelName in db.models) { + models[modelName] = db.models[modelName]; + } + // 将包含所有模型的models对象挂载到应用程序环境对象app上,方便在应用中使用模型进行数据库操作 + app.models = models; + // 调用传入的回调函数,传递null表示操作成功完成,无错误信息 + callback(null); + // 执行next函数,用于告知orm模块相关操作已完成,可继续后续流程(具体取决于orm模块的设计和使用方式) + next(); + }) + .catch(function (error) { + // 如果在加载模型过程中出现错误,在控制台打印错误信息,同时调用回调函数并传递错误对象,告知调用者操作失败 + console.error('加载模块出错 error: ' + err); + callback(error); + // 同样执行next函数,告知orm模块相关流程结束(即便出现错误) + next(); + }); + }); + } + })); } +// 将initialize函数作为模块的一个属性暴露出去,方便其他模块引入并调用该函数进行数据库初始化操作 module.exports.initialize = initialize; -module.exports.getDatabase = function() { - return global.database; + +// 定义一个函数用于获取全局的数据库实例对象,通过返回global对象上挂载的database属性(在initialize函数中进行挂载的)来实现 +module.exports.getDatabase = function () { + return global.database; } \ No newline at end of file diff --git a/modules/logger.js b/modules/logger.js index a811e85..fb0e1b4 100644 --- a/modules/logger.js +++ b/modules/logger.js @@ -1,20 +1,44 @@ +// 引入log4js模块,它是一个用于在Node.js应用中进行日志记录的常用库,能够方便地实现不同级别的日志输出以及日志的格式化、存储等功能 var log4js = require('log4js'); +// 使用log4js的configure方法进行日志配置,配置项以对象形式传入 log4js.configure({ - appenders: { cheese: { type: 'file', filename: 'cheese.log' } }, - categories: { default: { appenders: ['cheese'], level: 'error' } } + // 配置日志的输出目标(appenders),这里定义了一个名为'cheese'的输出配置 + appenders: { + // 'type'指定了输出类型为'file',即输出到文件 + // 'filename'指定了输出的文件名是'cheese.log',意味着日志信息将会被记录到该文件中 + cheese: { type: 'file', filename: 'cheese.log' } + }, + // 配置日志的分类(categories),用于将不同的日志记录器划分到不同的类别,并指定每个类别的相关属性 + categories: { + // 'default'表示默认的日志类别 + default: { + // 'appenders'数组指定了该类别使用的日志输出目标,这里只使用了前面定义的'cheese'输出目标 + appenders: ['cheese'], + // 'level'指定了该类别日志记录的级别,这里设置为'error',表示只有错误级别及以上的日志才会被记录到对应的输出目标中 + level: 'error' + } + } }); +// 将一个名为'logger'的函数作为模块的属性导出,用于获取日志记录器实例 exports.logger = function (level) { + // 通过log4js的getLogger方法获取名为'cheese'的日志记录器实例,后续可以使用这个实例来记录相应的日志信息 var logger = log4js.getLogger("cheese"); + // 设置该日志记录器的日志级别为'debug',这意味着从调试级别(最低级别)开始的所有日志都会被记录,覆盖了之前配置中'default'类别里设置的'error'级别(此处修改可能根据实际需求而定) logger.level = 'debug'; + // 返回配置好的日志记录器实例,外部模块可以调用该函数获取实例后进行日志记录操作 return logger; }; -// 配合 express 使用的方法 +// 以下是一段被注释掉的代码,从函数名和使用方式来看,它原本是用于配合Express框架使用的方法,用于在Express应用中集成log4js日志记录功能 // exports.use = function (app, level) { +// // 在Express应用中使用log4js的connectLogger中间件来记录请求相关的日志信息 +// // 首先通过log4js的getLogger方法获取名为'logInfo'的日志记录器实例(这里假设'logInfo'是之前定义好的某个日志记录器名称,实际可能需要准确配置) // app.use(log4js.connectLogger(log4js.getLogger('logInfo'), { +// // 设置日志记录的级别,它会尝试从传入的'level'参数获取对应级别,如果没有则使用默认的'debug'级别(这里的'levels'变量未在提供的代码中定义,可能是一个定义了不同日志级别映射关系的对象,实际应用中需要准确处理) // level: levels[level] || levels['debug'], +// // 定义日志记录的格式,这里使用了简单的格式字符串,指定记录请求的方法、URL以及响应状态等信息,方便后续查看请求相关的日志详情 // format: ':method :url :status' // })); // }; \ No newline at end of file diff --git a/modules/passport.js b/modules/passport.js index dfd4712..1f38ec8 100644 --- a/modules/passport.js +++ b/modules/passport.js @@ -1,86 +1,123 @@ +// 引入Passport模块,它是Node.js中用于处理用户认证的常用中间件,可方便地集成多种认证策略 const passport = require('passport'); +// 引入Passport的本地策略(LocalStrategy),通常用于基于用户名和密码的认证方式,比如常见的表单登录验证 const LocalStrategy = require('passport-local').Strategy; +// 引入Passport的HTTP Bearer策略(Strategy),常用于基于令牌(Token)的认证,比如JSON Web Tokens(JWT)认证场景 const Strategy = require('passport-http-bearer').Strategy; +// 引入jsonwebtoken模块,用于处理JSON Web Tokens(JWT)的生成、验证等操作 var jwt = require("jsonwebtoken"); - +// 引入Lodash库,它提供了很多实用的工具函数,用于处理数据、对象等,此处虽未明确体现具体使用的功能,但可能用于辅助数据操作等 var _ = require('lodash'); - +// 引入配置模块(config),并获取名为"jwt_config"的配置项,通常用于获取与JWT相关的配置信息,如密钥、过期时间等 var jwt_config = require("config").get("jwt_config"); // 通过登录函数初始化 /** - * 初始化 passport 框架 + * 初始化passport框架 + * 此函数的主要作用是配置Passport的不同认证策略,并将Passport初始化到给定的应用程序(app)中, + * 同时提供回调机制,方便在初始化完成后执行额外的操作。 * - * @param {[type]} app 全局应用程序 - * @param {[type]} loginFunc 登录函数 - * @param {Function} callback 回调函数 + * @param {[type]} app 全局应用程序,通常是Express等Web框架创建的应用实例,用于挂载中间件等操作。 + * @param {[type]} loginFunc 登录函数,用于执行具体的用户名和密码验证逻辑,比如查询数据库验证用户输入的用户名和密码是否匹配等操作。 + * @param {Function} callback 回调函数,在Passport初始化及相关策略配置完成后被调用,可用于执行后续自定义的初始化步骤等操作(可选参数)。 */ -module.exports.setup = function(app,loginFunc,callback) { - // 用户名密码 登录策略 - passport.use(new LocalStrategy( - function(username, password, done) { - if(!loginFunc) return done("登录验证函数未设置"); +module.exports.setup = function (app, loginFunc, callback) { + // 用户名密码 登录策略 + // 使用Passport的LocalStrategy配置基于用户名和密码的认证策略 + passport.use(new LocalStrategy( + // 定义验证逻辑函数,接收用户名、密码以及回调函数(done)作为参数 + function (username, password, done) { + // 如果没有传入登录验证函数(loginFunc),则直接通过回调函数(done)返回错误信息,表示登录验证函数未设置 + if (!loginFunc) return done("登录验证函数未设置"); - loginFunc(username,password,function(err,user) { - if(err) return done(err); - return done(null, user); - }); - }) - ); + // 调用传入的登录验证函数(loginFunc),传入用户名和密码进行验证,验证完成后会在回调函数中返回结果 + loginFunc(username, password, function (err, user) { + // 如果验证过程中出现错误,通过回调函数(done)返回错误信息给Passport,告知认证失败原因 + if (err) return done(err); + // 如果验证成功,通过回调函数(done)返回用户信息(通常是包含用户相关数据的对象)给Passport,表示认证成功 + return done(null, user); + }); + } + )); - // token 验证策略 - passport.use(new Strategy( - function(token, done) { - jwt.verify(token, jwt_config.get("secretKey"), function (err, decode) { - if (err) { return done("验证错误"); } - return done(null, decode); - }); - } - )); + // token验证策略 + // 使用Passport的HTTP Bearer策略配置基于令牌(Token)的认证策略 + passport.use(new Strategy( + // 定义验证逻辑函数,接收令牌(token)以及回调函数(done)作为参数 + function (token, done) { + // 使用jsonwebtoken模块的verify方法验证传入的令牌(token)是否有效, + // 传入令牌、配置中的密钥(jwt_config.get("secretKey"))以及验证回调函数,验证回调函数接收验证结果(err)和解析后的令牌数据(decode)作为参数 + jwt.verify(token, jwt_config.get("secretKey"), function (err, decode) { + // 如果验证过程中出现错误,通过回调函数(done)返回错误信息给Passport,表示令牌验证失败 + if (err) { return done("验证错误"); } + // 如果验证成功,通过回调函数(done)返回解析后的令牌数据(decode)给Passport,表示令牌验证通过 + return done(null, decode); + }); + } + )); - // 初始化passport模块 - app.use(passport.initialize()); + // 初始化passport模块 + // 将Passport中间件初始化到应用程序(app)中,使其能够在后续的请求处理流程中生效,用于处理各种认证相关的操作 + app.use(passport.initialize()); - if(callback) callback(); + // 如果传入了回调函数(callback),则执行该回调函数,用于在初始化完成后执行额外的自定义操作 + if (callback) callback(); }; /** * 登录验证逻辑 + * 此函数主要用于处理基于用户名和密码的登录请求验证逻辑,通过调用Passport的认证中间件进行验证, + * 根据验证结果生成相应的响应信息返回给客户端,包括在验证成功时生成并返回JWT令牌等操作。 * - * @param {[type]} req 请求 - * @param {[type]} res 响应 - * @param {Function} next [description] + * @param {[type]} req 请求对象,包含了客户端发送的请求相关信息,如请求头、请求体等内容,常用于获取用户名、密码等登录信息。 + * @param {[type]} res 响应对象,用于向客户端发送响应信息,如返回登录成功或失败的消息、生成的令牌等内容。 + * @param {Function} next 传递事件函数,用于将请求传递给下一个中间件继续处理(在Express等框架的中间件链机制中使用),此处未明确体现后续传递逻辑,但遵循中间件规范保留该参数。 */ -module.exports.login = function(req,res,next) { +module.exports.login = function (req, res, next) { + // 使用Passport的authenticate方法,传入'local'表示采用之前配置的基于用户名和密码的本地认证策略进行认证, + // 同时传入一个回调函数用于处理认证结果,该回调函数接收认证过程中的错误(err)、认证通过后的用户信息(user)以及额外的提示信息(info)作为参数 + passport.authenticate('local', function (err, user, info) { + // 如果认证过程中出现错误,使用响应对象(res)的sendResult方法(这里假设是自定义的用于统一返回响应格式的方法)向客户端发送包含错误状态码(400表示请求错误)和错误信息的响应 + if (err) return res.sendResult(null, 400, err); + // 如果没有获取到用户信息(即认证失败,未找到匹配的用户),同样使用响应对象的sendResult方法向客户端发送包含错误状态码和相应错误提示信息的响应 + if (!user) return res.sendResult(null, 400, "参数错误"); - passport.authenticate('local', function(err, user, info) { - - if(err) return res.sendResult(null,400,err); - if(!user) return res.sendResult(null,400,"参数错误"); - - // 获取角色信息 - var token = jwt.sign({"uid":user.id,"rid":user.rid}, jwt_config.get("secretKey"), {"expiresIn": jwt_config.get("expiresIn")}); - user.token = "Bearer " + token; - return res.sendResult(user,200,'登录成功'); - })(req, res, next); - -} + // 获取角色信息 + // 使用jsonwebtoken模块的sign方法生成JWT令牌,传入包含用户ID(uid)和角色ID(rid)的对象、配置中的密钥以及令牌过期时间等配置信息,生成一个有效的JWT令牌 + var token = jwt.sign({"uid": user.id, "rid": user.rid}, jwt_config.get("secretKey"), {"expiresIn": jwt_config.get("expiresIn")}); + // 将生成的令牌添加到用户对象中,并添加"Bearer "前缀,符合Bearer Token的规范格式,方便后续在请求头中传递和验证 + user.token = "Bearer " + token; + // 使用响应对象的sendResult方法向客户端发送包含用户信息、成功状态码(200)以及登录成功消息的响应,表示登录操作成功完成,并返回相关用户数据和令牌 + return res.sendResult(user, 200, '登录成功'); + })(req, res, next); +}; /** * token验证函数 + * 此函数用于处理基于令牌(Token)的验证逻辑,通过调用Passport的相应认证中间件验证传入的令牌是否有效, + * 根据验证结果设置请求对象(req)中的用户信息,并决定是否将请求传递给下一个中间件继续处理。 * - * @param {[type]} req 请求对象 - * @param {[type]} res 响应对象 - * @param {Function} next 传递事件函数 + * @param {[type]} req 请求对象,包含了客户端发送的请求相关信息以及在验证通过后可用于存储用户相关数据等内容,方便后续中间件使用验证后的用户信息进行业务逻辑处理。 + * @param {[type]} res 响应对象,用于向客户端发送响应信息,如在令牌验证失败时返回相应的错误消息等内容。 + * @param {Function} next 传递事件函数,用于将请求传递给下一个中间件继续处理,在令牌验证通过后会调用该函数将请求传递下去,让后续中间件继续执行相应的业务逻辑。 */ -module.exports.tokenAuth = function(req,res,next) { - passport.authenticate('bearer', { session: false },function(err,tokenData) { - if(err) return res.sendResult(null,400,'无效token'); - if(!tokenData) return res.sendResult(null,400,'无效token'); - req.userInfo = {}; - req.userInfo.uid = tokenData["uid"]; - req.userInfo.rid = tokenData["rid"]; - next(); - })(req, res, next); -} +module.exports.tokenAuth = function (req, res, next) { + // 使用Passport的authenticate方法,传入'bearer'表示采用之前配置的基于HTTP Bearer的认证策略进行令牌验证, + // 同时传入{ session: false }表示不依赖会话(Session)进行验证(常用于无状态的API认证场景,如基于JWT的认证), + // 并传入一个回调函数用于处理验证结果,该回调函数接收验证过程中的错误(err)以及验证通过后的令牌数据(tokenData)作为参数 + passport.authenticate('bearer', { session: false }, function (err, tokenData) { + // 如果验证过程中出现错误,使用响应对象(res)的sendResult方法向客户端发送包含错误状态码(400表示请求错误)和相应错误提示信息(无效token)的响应 + if (err) return res.sendResult(null, 400, '无效token'); + // 如果没有获取到有效的令牌数据(即令牌验证失败),同样使用响应对象的sendResult方法向客户端发送包含错误状态码和相应错误提示信息的响应 + if (!tokenData) return res.sendResult(null, 400, '无效token'); + // 如果令牌验证通过,在请求对象(req)中创建一个空的用户信息对象(userInfo),用于存储从令牌中解析出的相关用户信息,方便后续中间件使用 + req.userInfo = {}; + // 将从令牌数据(tokenData)中解析出的用户ID(uid)存储到请求对象的用户信息对象中 + req.userInfo.uid = tokenData["uid"]; + // 将从令牌数据(tokenData)中解析出的角色ID(rid)存储到请求对象的用户信息对象中 + req.userInfo.rid = tokenData["rid"]; + // 调用传递事件函数(next),将请求传递给下一个中间件继续处理,表示令牌验证通过,后续中间件可以基于请求对象中的用户信息进行相应的业务逻辑操作 + next(); + })(req, res, next); +} \ No newline at end of file diff --git a/modules/resextra.js b/modules/resextra.js index 313da22..8c5d67e 100644 --- a/modules/resextra.js +++ b/modules/resextra.js @@ -1,17 +1,29 @@ // 添加统一的返回结果方法 -module.exports = function(req, res, next){ - res.sendResult = function(data,code,message) { - var fmt = req.query.fmt ? req.query.fmt : "rest"; - if(fmt == "rest") { - res.json( - { - "data" : data, - "meta" : { - "msg" : message, - "status" : code - } - }); - } - }; - next(); +// 此代码将一个函数作为模块的导出内容,该函数很可能作为中间件在 Express 等 Node.js 的 Web 框架中使用, +// 目的是为响应对象(res)添加一个自定义的 `sendResult` 方法,用于统一格式化返回给客户端的结果数据。 +module.exports = function (req, res, next) { + // 为响应对象(res)添加 `sendResult` 方法,用于按照特定格式向客户端返回结果数据, + // 该方法接收要返回的数据(data)、状态码(code)以及提示消息(message)作为参数。 + res.sendResult = function (data, code, message) { + // 获取请求对象(req)中查询参数(query)里名为 `fmt` 的参数值,若不存在则默认为 "rest", + // 这个参数用于指定返回结果的格式,这里根据不同的值可以实现不同的返回格式逻辑(目前仅实现了 "rest" 格式)。 + var fmt = req.query.fmt? req.query.fmt : "rest"; + // 判断返回结果的格式是否为 "rest",如果是,则按照相应的 JSON 格式进行数据组装并返回给客户端。 + if (fmt == "rest") { + res.json( + { + // 将传入的要返回的数据(data)放置在 "data" 字段下。 + "data": data, + "meta": { + // 将传入的提示消息(message)放置在 "meta" 字段下的 "msg" 子字段中,用于告知客户端相关操作的提示信息。 + "msg": message, + // 将传入的状态码(code)放置在 "meta" 字段下的 "status" 子字段中,用于告知客户端操作的状态,比如 200 表示成功,400 表示客户端错误等。 + "status": code + } + }); + } + }; + // 调用 `next` 函数,将请求传递给下一个中间件继续处理,遵循 Express 等框架中间件的执行顺序和规范, + // 保证整个请求处理流程能够继续进行下去。 + next(); } \ No newline at end of file diff --git a/modules/ueditor.js b/modules/ueditor.js index 3d8ccb0..fcba046 100644 --- a/modules/ueditor.js +++ b/modules/ueditor.js @@ -1,67 +1,101 @@ +// 引入Lodash库,它提供了很多实用的工具函数,用于处理数据、对象、数组等操作,虽然此处未明确体现具体使用的功能,但后续可能会借助它进行一些便捷的数据处理 var _ = require('lodash'); +// 引入Node.js的path模块,用于处理文件路径相关的操作,比如拼接、解析路径等 var path = require("path"); +// 引入Busboy模块,它常用于处理文件上传的中间件,能够方便地解析包含文件的HTTP请求中的文件数据 var Busboy = require('busboy'); +// 引入Node.js的文件系统模块fs,用于对文件进行读写、查询目录等操作 var fs = require("fs"); +// 引入uniqid模块,用于生成唯一的标识符,在这里可能用于为上传的文件生成唯一的文件名 var uniqid = require('uniqid'); -var ueditor_config = require(path.join(process.cwd(),"/config/ueditor.config.js")); +// 引入UEditor的配置文件,通过拼接当前工作目录和配置文件的相对路径来获取其准确路径,该配置文件可能包含了UEditor相关的各种配置参数,如上传路径、允许的文件类型等 +var ueditor_config = require(path.join(process.cwd(), "/config/ueditor.config.js")); +// 引入项目的上传配置信息,通过配置模块(config)获取名为"upload_config"的配置项,里面应该包含了如上传目录、基础URL等与上传相关的配置内容 var upload_config = require('config').get("upload_config"); +// 定义允许上传的文件类型列表,以逗号分隔的字符串形式表示,目前包含了常见的图片文件类型以及ico、bmp文件类型 var filetype = 'jpg,png,gif,ico,bmp'; -module.exports = function(req,res,next) { - if(req.query.action == "config") { - // 吐给客户端配置信息 - res.jsonp(ueditor_config); - } else if (req.query.action === 'uploadimage' || req.query.action === 'uploadfile' || req.query.action === 'uploadvideo') { - var busboy = new Busboy({ headers: req.headers }); - busboy.on('file', function (fieldname, file, filename, encoding, mimetype) { - var fileExtArray = filename.split("."); - var ext = fileExtArray[fileExtArray.length - 1]; - var save_filename = uniqid() + "." + ext; - var savePath = path.join(process.cwd(),upload_config.get("upload_ueditor"),save_filename); - file.on('end', function () { - var result = { - 'url': upload_config.get("baseURL")+"/" + upload_config.get("upload_ueditor") + "/" + save_filename, - 'title': req.body && req.body.pictitle || filename, - 'original': filename, - 'state': 'SUCCESS' - }; - if(req.query.encode) { - res.jsonp(result); - } else { +// 将一个函数作为模块的导出内容,这个函数很可能作为中间件在Express等Node.js的Web框架中使用,用于处理不同UEditor相关的请求操作,比如获取配置、上传文件、获取文件列表等 +module.exports = function (req, res, next) { + // 判断请求中的查询参数action的值是否为"config",如果是,则表示客户端请求获取UEditor的配置信息 + if (req.query.action == "config") { + // 使用res.jsonp方法将UEditor的配置信息(ueditor_config)返回给客户端,jsonp是一种跨域数据传输的方式,常用于解决浏览器的同源策略限制问题,使得客户端能够获取到配置数据 + res.jsonp(ueditor_config); + } else if (req.query.action === 'uploadimage' || req.query.action === 'uploadfile' || req.query.action === 'uploadvideo') { + // 创建一个Busboy实例,用于解析包含文件上传的请求,传入请求头(headers)信息,使得Busboy能够根据请求头中的相关信息(如Content-Type等)来正确解析文件数据 + var busboy = new Busboy({ headers: req.headers }); - res.redirect(upload_config.get("simple_upload_redirect") + "?result=" + JSON.stringify(result)); - // res.redirect(result.url); - } - - }); + // 监听Busboy实例的'file'事件,当解析到文件数据时,该事件会被触发,事件回调函数接收多个参数,用于获取文件相关的各种信息 + busboy.on('file', function (fieldname, file, filename, encoding, mimetype) { + // 将文件名(filename)按"."进行分割,得到一个包含文件名各部分的数组,用于提取文件的扩展名 + var fileExtArray = filename.split("."); + // 获取文件扩展名,即分割后的数组中的最后一个元素 + var ext = fileExtArray[fileExtArray.length - 1]; + // 使用uniqid模块生成一个唯一的标识符,并与文件扩展名拼接起来,作为保存文件时使用的文件名,这样可以确保文件名的唯一性,避免文件覆盖等问题 + var save_filename = uniqid() + "." + ext; + // 拼接文件保存的完整路径,通过结合当前工作目录、配置中的上传目录(upload_config.get("upload_ueditor"))以及生成的文件名(save_filename)来确定最终保存位置 + var savePath = path.join(process.cwd(), upload_config.get("upload_ueditor"), save_filename); - file.pipe(fs.createWriteStream(savePath)); - }); - req.pipe(busboy); - } else if(req.query.action === 'listimage') { - fs.readdir(path.join(process.cwd(),upload_config.get("upload_ueditor")),function(err, files){ - if(err) return res.end(); - var total = files.length; + // 监听文件流(file)的'end'事件,当文件数据全部读取完毕后,该事件会被触发,在这里可以进行一些后续操作,比如组装返回给客户端的文件上传结果信息 + file.on('end', function () { + // 组装文件上传成功后的结果对象,包含文件的访问URL、标题(可根据请求体中的pictitle字段获取,如果不存在则使用原始文件名)、原始文件名以及表示上传状态为成功的标志 + var result = { + 'url': upload_config.get("baseURL") + "/" + upload_config.get("upload_ueditor") + "/" + save_filename, + 'title': req.body && req.body.pictitle || filename, + 'original': filename, + 'state': 'SUCCESS' + }; + // 判断请求中是否包含encode参数,如果有,则使用res.jsonp方法将结果对象以JSONP的形式返回给客户端,同样是考虑到跨域等情况的一种数据返回方式 + if (req.query.encode) { + res.jsonp(result); + } else { + // 如果没有encode参数,使用res.redirect方法进行重定向,重定向的URL由配置中的简单上传重定向地址(upload_config.get("simple_upload_redirect"))和文件上传结果信息(经过JSON.stringify转换为字符串形式)拼接而成,这样客户端可以根据重定向后的地址获取到上传结果信息 + // 另一个被注释掉的res.redirect(result.url),原本可能是直接重定向到文件的访问URL,但这里采用了传递结果信息的重定向方式 + res.redirect(upload_config.get("simple_upload_redirect") + "?result=" + JSON.stringify(result)); + } + }); - var filelist = []; - var total = 0; - _(files).forEach(function(file){ - var fileExtArray = file.split("."); - var ext = fileExtArray[fileExtArray.length - 1]; - if (filetype.indexOf(ext.toLowerCase()) >= 0) { - var result_file = {}; - result_file.url = upload_config.get("baseURL")+"/" + upload_config.get("upload_ueditor") + "/" + file; - filelist.push(result_file); - total ++; - } - }); - res.jsonp({ - "state": "SUCCESS", - "list": filelist, - "start": 1, - "total": total - }); - }) - } + // 将文件流(file)通过管道(pipe)写入到创建的可写文件流(fs.createWriteStream(savePath))中,实现将上传的文件保存到指定的文件路径下 + file.pipe(fs.createWriteStream(savePath)); + }); + + // 将请求对象(req)通过管道(pipe)传入到Busboy实例中,触发Busboy开始解析请求中的文件数据,从而进入上述的文件上传处理流程 + req.pipe(busboy); + } else if (req.query.action === 'listimage') { + // 使用文件系统模块(fs)的readdir方法读取指定目录下的所有文件,目录路径通过结合当前工作目录和配置中的上传目录(upload_config.get("upload_ueditor"))来确定,读取完成后会调用回调函数处理结果(err表示读取过程中是否出现错误,files表示读取到的文件列表) + fs.readdir(path.join(process.cwd(), upload_config.get("upload_ueditor")), function (err, files) { + // 如果读取过程中出现错误,直接结束响应,不返回任何数据给客户端(这里可以考虑返回更合适的错误信息给客户端) + if (err) return res.end(); + // 初始化一个变量用于统计符合条件的文件总数,初始值为0 + var total = 0; + // 创建一个空数组,用于存放符合条件的文件信息,后续会将满足文件类型要求的文件相关信息添加到这个数组中 + var filelist = []; + + // 使用Lodash的forEach方法遍历读取到的所有文件,对每个文件进行相关处理 + _(files).forEach(function (file) { + // 将文件名按"."进行分割,获取文件扩展名,用于后续判断文件类型是否符合要求 + var fileExtArray = file.split("."); + var ext = fileExtArray[fileExtArray.length - 1]; + // 判断文件扩展名是否在允许的文件类型列表(filetype)中(将扩展名转换为小写后进行判断),如果是,则表示该文件符合要求,进行相应的信息组装和添加到文件列表操作 + if (filetype.indexOf(ext.toLowerCase()) >= 0) { + var result_file = {}; + // 组装文件的访问URL,格式与前面文件上传成功后的URL格式类似,通过配置中的基础URL、上传目录以及文件名来确定 + result_file.url = upload_config.get("baseURL") + "/" + upload_config.get("upload_ueditor") + "/" + file; + // 将组装好的文件信息对象添加到文件列表数组中 + filelist.push(result_file); + // 符合条件的文件总数加1 + total++; + } + }); + + // 使用res.jsonp方法将包含文件列表信息、状态(SUCCESS表示成功获取列表)、起始索引(这里固定为1)以及文件总数的结果对象返回给客户端,同样采用JSONP的方式考虑跨域等情况进行数据传输 + res.jsonp({ + "state": "SUCCESS", + "list": filelist, + "start": 1, + "total": total + }); + }) + } } \ No newline at end of file diff --git a/public2/ueditor/dialogs/map/map.html b/public2/ueditor/dialogs/map/map.html index e763b8e..ab3e489 100644 --- a/public2/ueditor/dialogs/map/map.html +++ b/public2/ueditor/dialogs/map/map.html @@ -2,133 +2,193 @@ + + + + -
- - - - - - - - - -
::
-
+
+ + + + + + + + + + + + +
::
+
+ +
+ + editor.execCommand('inserthtml', ''); + } + }; + document.getElementById("address").focus(); + diff --git a/public2/ueditor/dialogs/map/show.html b/public2/ueditor/dialogs/map/show.html index 329cfeb..9eff473 100644 --- a/public2/ueditor/dialogs/map/show.html +++ b/public2/ueditor/dialogs/map/show.html @@ -1,11 +1,15 @@ + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - - - + + + + + + 百度地图API自定义地图 + + - -
+ + +
+ diff --git a/public2/ueditor/dialogs/music/music.css b/public2/ueditor/dialogs/music/music.css index 8fb7a94..5b0f28a 100644 --- a/public2/ueditor/dialogs/music/music.css +++ b/public2/ueditor/dialogs/music/music.css @@ -1,30 +1,190 @@ -.wrapper{margin: 5px 10px;} +/* 定义类名为.wrapper 的元素样式 */ +.wrapper{ + margin: 5px 10px; + /* 设置元素的外边距,上下外边距为 5 像素,左右外边距为 10 像素,用于控制该元素与周围元素在页面中的间隔距离 */ +} -.searchBar{height:30px;padding:7px 0 3px;text-align:center;} -.searchBtn{font-size:13px;height:24px;} +/* 定义类名为.searchBar 的元素样式 */ +.searchBar{ + height: 30px; + padding: 7px 0 3px; + text-align: center; + /* 设置元素的高度为 30 像素,内边距方面,上方内边距为 7 像素,下方内边距为 3 像素,左右内边距为 0 像素,使元素内部内容在垂直方向上有一定间隔;同时将文本水平居中对齐,常用于包含搜索相关输入框、按钮等元素的容器,使其内部元素布局更规整 */ +} -.resultBar{width:460px;margin:5px auto;border: 1px solid #CCC;border-radius: 5px;box-shadow: 2px 2px 5px #D3D6DA;overflow: hidden;} +/* 定义类名为.searchBtn 的元素样式 */ +.searchBtn{ + font-size: 13px; + height: 24px; + /* 设置元素的字体大小为 13 像素,高度为 24 像素,可用于按钮等交互元素,使其呈现出合适的尺寸和文字显示大小,方便用户操作与查看 */ +} -.listPanel{overflow: hidden;} -.panelon{display:block;} -.paneloff{display:none} +/* 定义类名为.resultBar 的元素样式 */ +.resultBar{ + width: 460px; + margin: 5px auto; + border: 1px solid #CCC; + border-radius: 5px; + box-shadow: 2px 2px 5px #D3D6DA; + overflow: hidden; + /* 设置元素的宽度为 460 像素,使其具有固定宽度;外边距方面,上下外边距为 5 像素,左右自动(auto)居中,让该元素在页面中水平居中显示;边框为 1 像素宽的浅灰色(#CCC)实线;添加 5 像素的圆角效果(border-radius),使边框角变得圆润,提升外观美感;添加阴影效果(box-shadow),营造出立体层次感;同时设置溢出内容隐藏(overflow: hidden),防止内部元素超出该容器范围显示,常用于展示搜索结果等内容的容器样式设置 */ +} -.page{width:220px;margin:20px auto;overflow: hidden;} -.pageon{float:right;width:24px;line-height:24px;height:24px;margin-right: 5px;background: none;border: none;color: #000;font-weight: bold;text-align:center} -.pageoff{float:right;width:24px;line-height:24px;height:24px;cursor:pointer;background-color: #fff; - border: 1px solid #E7ECF0;color: #2D64B3;margin-right: 5px;text-decoration: none;text-align:center;} +/* 定义类名为.listPanel 的元素样式 */ +.listPanel{ + overflow: hidden; + /* 设置元素的溢出内容隐藏,通常用于包含多个子元素且希望控制子元素显示范围,避免出现滚动条或者超出部分不显示等布局情况,常作为列表展示相关的父容器样式 */ +} -.m-box{width:460px;} -.m-m{float: left;line-height: 20px;height: 20px;} -.m-h{height:24px;line-height:24px;padding-left: 46px;background-color:#FAFAFA;border-bottom: 1px solid #DAD8D8;font-weight: bold;font-size: 12px;color: #333;} -.m-l{float:left;width:40px; } -.m-t{float:left;width:140px;} -.m-s{float:left;width:110px;} -.m-z{float:left;width:100px;} -.m-try-t{float: left;width: 60px;;} +/* 定义类名为.panelon 的元素样式 */ +.panelon{ + display: block; + /* 将元素设置为块级元素显示,会独占一行,常用于控制元素的显示与隐藏逻辑,当需要显示某个面板或模块时应用此样式 */ +} -.m-try{float:left;width:20px;height:20px;background:url('http://static.tieba.baidu.com/tb/editor/images/try_music.gif') no-repeat ;} -.m-trying{float:left;width:20px;height:20px;background:url('http://static.tieba.baidu.com/tb/editor/images/stop_music.gif') no-repeat ;} +/* 定义类名为.paneloff 的元素样式 */ +.paneloff{ + display: none; + /* 将元素设置为隐藏状态,不显示在页面上,同样用于元素的显示与隐藏逻辑控制,比如隐藏不需要展示的面板或模块时应用此样式 */ +} -.loading{width:95px;height:7px;font-size:7px;margin:60px auto;background:url(http://static.tieba.baidu.com/tb/editor/images/loading.gif) no-repeat} -.empty{width:300px;height:40px;padding:2px;margin:50px auto;line-height:40px; color:#006699;text-align:center;} \ No newline at end of file +/* 定义类名为.page 的元素样式 */ +.page{ + width: 220px; + margin: 20px auto; + overflow: hidden; + /* 设置元素的宽度为 220 像素,外边距上下为 20 像素且左右自动(auto)居中,使其在页面中水平居中显示;同样设置溢出内容隐藏,可用于分页相关的导航元素容器样式,控制内部分页链接等元素的布局范围 */ +} + +/* 定义类名为.pageon 的元素样式 */ +.pageon{ + float: right; + width: 24px; + line-height: 24px; + height: 24px; + margin-right: 5px; + background: none; + border: none; + color: #000; + font-weight: bold; + text-align: center; + /* 将元素设置为右浮动(float: right),使其在父容器内靠右排列;宽度为 24 像素,高度为 24 像素,行高也为 24 像素,使文本在元素内垂直居中;右边距为 5 像素,与其他相邻元素隔开一定距离;背景设置为无(none),边框设置为无(none),文本颜色为黑色(#000),字体加粗(font-weight: bold),文本水平居中对齐(text-align: center),这种样式可能用于表示当前选中的分页链接等元素,使其在页面上突出显示 */ +} + +/* 定义类名为.pageoff 的元素样式 */ +.pageoff{ + float: right; + width: 24px; + line-height: 24px; + height: 24px; + cursor: pointer; + background-color: #fff; + border: 1px solid #E7ECF0; + color: #2D64B3; + margin-right: 5px; + text-decoration: none; + text-align: center; + /* 同样设置为右浮动,尺寸方面与.pageon 类似,设置宽度、高度和行高都为 24 像素;鼠标指针悬停时变为手型(cursor: pointer),表示可点击交互;背景颜色为白色(#fff),边框为 1 像素宽的淡蓝色(#E7ECF0)实线;文本颜色为浅蓝色(#2D64B3),右边距为 5 像素,去除文本的下划线装饰(text-decoration: none),文本水平居中对齐,这种样式可能用于表示未选中的分页链接等可点击元素,通过不同的样式与.pageon 区分开来,便于用户识别和操作 */ +} + +/* 定义类名为.m-box 的元素样式 */ +.m-box{ + width: 460px; + /* 设置元素的宽度为 460 像素,可作为一个整体的容器,控制内部相关元素的布局宽度范围 */ +} + +/* 定义类名为.m-m 的元素样式 */ +.m-m{ + float: left; + line-height: 20px; + height: 20px; + /* 将元素设置为左浮动(float: left),使其在父容器内靠左排列;行高为 20 像素,高度也为 20 像素,可用于设置文本等内容在垂直方向上的对齐和显示高度,常用于包含多个并列信息的布局场景,比如列表项中的不同字段内容展示 */ +} + +/* 定义类名为.m-h 的元素样式 */ +.m-h{ + height: 24px; + line-height: 24px; + padding-left: 46px; + background-color: #FAFAFA; + border-bottom: 1px solid #DAD8D8; + font-weight: bold; + font-size: 12px; + color: #333; + /* 设置元素的高度为 24 像素,行高与高度相同,使文本垂直居中;左边内边距为 46 像素,增加左侧空白间隔;背景颜色为浅灰色(#FAFAFA),底部添加 1 像素宽的稍深一点的灰色(#DAD8D8)边框,用于区分不同部分;字体加粗,字体大小为 12 像素,文本颜色为深灰色(#333),这种样式可能用于标题栏等元素,使其在页面上突出显示且与其他内容区分开来 */ +} + +/* 定义类名为.m-l 的元素样式 */ +.m-l{ + float: left; + width: 40px; + /* 将元素设置为左浮动,宽度设置为 40 像素,常用于在一行内划分出固定宽度的区域,放置相应的内容,比如列表项中的某个字段内容展示 */ +} + +/* 定义类名为.m-t 的元素样式 */ +.m-t{ + float: left; + width: 140px; + /* 将元素设置为左浮动,宽度设置为 140 像素,同样用于在一行内划分出特定宽度区域来展示相关内容,与其他浮动元素一起实现多列信息的布局展示 */ +} + +/* 定义类名为.m-s 的元素样式 */ +.m-s{ + float: left; + width: 110px; + /* 将元素设置为左浮动,宽度设置为 110 像素,也是用于布局多列信息,按照设定的宽度分配空间展示不同内容 */ +} + +/* 定义类名为.m-z 的元素样式 */ +.m-z{ + float: left; + width: 100px; + /* 将元素设置为左浮动,宽度设置为 100 像素,与其他浮动元素配合实现一行内多列信息展示的布局效果 */ +} + +/* 定义类名为.m-try-t 的元素样式 */ +.m-try-t{ + float: left; + width: 60px; + /* 将元素设置为左浮动,宽度设置为 60 像素,可用于在布局中划分出特定宽度区域来放置相应的元素或展示内容 */ +} + +/* 定义类名为.m-try 的元素样式 */ +.m-try{ + float: left; + width: 20px; + height: 20px; + background: url('http://static.tieba.baidu.com/tb/editor/images/try_music.gif') no-repeat ; + /* 将元素设置为左浮动,宽度为 20 像素,高度为 20 像素,并设置背景图片,图片不重复平铺(no-repeat),该样式可能用于展示一个特定的音乐播放相关的图标等元素,通过背景图片呈现出可视化的效果 */ +} + +/* 定义类名为.m-trying 的元素样式 */ +.m-trying{ + float: left; + width: 20px; + height: 20px; + background: url('http://static.tieba.baidu.com/tb/editor/images/stop_music.gif') no-repeat ; + /* 同样设置为左浮动,尺寸与.m-try 相同,也是通过设置不同的背景图片(这里是停止音乐相关的图标图片)且不重复平铺,用于呈现另一种音乐相关操作的可视化图标元素,与.m-try 样式配合实现音乐播放相关的交互界面展示 */ +} + +/* 定义类名为.loading 的元素样式 */ +.loading{ + width: 95px; + height: 7px; + font-size: 7px; + margin: 60px auto; + background: url(http://static.tieba.baidu.com/tb/editor/images/loading.gif) no-repeat; + /* 设置元素的宽度为 95 像素,高度为 7 像素,字体大小为 7 像素,外边距上下为 60 像素且左右自动(auto)居中,使其在页面中水平居中显示;通过设置背景图片(loading 相关的动图,通常用于表示加载状态)且不重复平铺,用于展示加载中的可视化效果,提示用户当前正在进行数据加载等操作 */ +} + +/* 定义类名为.empty 的元素样式 */ +.empty{ + width: 300px; + height: 40px; + padding: 2px; + margin: 50px auto; + line-height: 40px; + color: #006699; + text-align: center; + /* 设置元素的宽度为 300 像素,高度为 40 像素,内边距为 2 像素,外边距上下为 50 像素且左右自动(auto)居中,使其在页面中水平居中显示;行高与高度相同,使文本垂直居中;文本颜色为浅蓝色(#006699),文本水平居中对齐,这种样式常用于当没有相关数据时,展示一个提示信息的区域,告知用户当前无数据等情况 */ +} \ No newline at end of file diff --git a/public2/ueditor/dialogs/music/music.html b/public2/ueditor/dialogs/music/music.html index e7ef04f..ae18602 100644 --- a/public2/ueditor/dialogs/music/music.html +++ b/public2/ueditor/dialogs/music/music.html @@ -2,31 +2,50 @@ + 插入音乐 + + + -
- + + \ No newline at end of file diff --git a/public2/ueditor/dialogs/music/music.js b/public2/ueditor/dialogs/music/music.js index 1c538bf..44231be 100644 --- a/public2/ueditor/dialogs/music/music.js +++ b/public2/ueditor/dialogs/music/music.js @@ -1,52 +1,74 @@ function Music() { this.init(); } +// 定义一个名为 'Music' 的构造函数,当创建 'Music' 类的实例时,会自动调用 'init' 方法,用于初始化音乐相关的一些设置和绑定事件等操作,这是面向对象编程中构造函数的常见用法,用于创建具有特定功能和属性的对象实例。 + (function () { var pages = [], panels = [], selectedItem = null; + // 创建三个私有变量,'pages' 数组用于存储分页相关的元素标识(可能是页面上分页按钮等元素的 ID 之类),'panels' 数组用于存储页面面板相关的元素标识(可能是用于展示不同页面内容的面板元素 ID),'selectedItem' 初始化为 null,用于记录用户选择的音乐相关信息(比如歌曲对象等),这几个变量在函数内部使用,外部无法直接访问,起到了数据封装的作用。 + Music.prototype = { - total:70, - pageSize:10, - dataUrl:"http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.common", - playerUrl:"http://box.baidu.com/widget/flash/bdspacesong.swf", + total: 70, + pageSize: 10, + dataUrl: "http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.common", + playerUrl: "http://box.baidu.com/widget/flash/bdspacesong.swf", + // 在 'Music' 类的原型对象上定义了四个属性。'total' 表示总的数据量(可能是搜索结果的总数之类),初始值为 70;'pageSize' 表示每页显示的数据条数,初始值为 10,用于分页功能相关计算;'dataUrl' 定义了获取音乐数据的 API 地址,指向百度音乐的一个搜索接口,通过向这个接口发送请求来获取音乐相关信息;'playerUrl' 定义了音乐播放器对应的 Flash 文件的 URL 地址,用于后续创建音乐播放相关的 HTML 元素嵌入到页面中实现音乐播放功能。 - init:function () { + init: function () { var me = this; + // 在 'init' 方法内部,首先将当前对象(this)赋值给变量'me',方便在内部函数中引用外部对象的属性和方法,这是一种常见的解决 JavaScript 中 this 指针指向问题的技巧,尤其是在事件回调函数中使用时。 + domUtils.on($G("J_searchName"), "keyup", function (event) { var e = window.event || event; if (e.keyCode == 13) { me.dosearch(); } }); + // 使用 'domUtils'(可能是自定义的 DOM 操作工具对象,包含处理 DOM 事件绑定等功能的函数)的 'on' 方法,为页面中 id 为 'J_searchName' 的元素(可能是一个输入框,用于输入搜索关键词)绑定 'keyup' 键盘按键抬起事件监听器。在事件回调函数中,先处理浏览器兼容性问题(获取正确的事件对象,因为不同浏览器获取事件对象的方式略有不同,IE 使用 'window.event',其他标准浏览器使用传入的参数 'event'),然后判断按下的键码(keyCode)是否为 13(回车键的键码),如果是回车键按下,则调用当前对象(通过'me' 引用)的 'dosearch' 方法,实现用户在输入框中输入关键词后按回车键触发搜索的功能。 + + domUtils.on($G("J_searchName"), "click", function () { + me.dosearch(); + }); + // 同样使用 'domUtils' 的 'on' 方法,为 id 为 'J_searchName' 的元素绑定 'click' 点击事件监听器,当用户点击该元素时,直接调用 'dosearch' 方法,不过通常输入框点击事件的使用场景较少,这里可能是一种额外的触发搜索方式或者是代码冗余(具体看实际需求),正常更常见的是通过回车键触发搜索。 + domUtils.on($G("J_searchBtn"), "click", function () { me.dosearch(); }); + // 使用 'domUtils' 为页面中 id 为 'J_searchBtn' 的元素(可能是一个按钮,用于触发音乐搜索操作)绑定 'click' 点击事件监听器,当用户点击这个按钮时,调用 'dosearch' 方法,触发音乐搜索逻辑,这是比较常见的通过按钮点击来执行搜索功能的实现方式。 }, - callback:function (data) { + + callback: function (data) { var me = this; me.data = data.song_list; setTimeout(function () { $G('J_resultBar').innerHTML = me._renderTemplate(data.song_list); }, 300); + // 定义 'callback' 方法,用于接收从服务器获取音乐数据后的回调处理。首先将传入的 'data' 参数中的'song_list' 属性值(可能是包含歌曲信息的数组)赋值给当前对象(通过'me' 引用)的 'data' 属性,以便后续在其他方法中可以访问这些歌曲数据。然后使用'setTimeout' 函数,延迟 300 毫秒后执行一个匿名函数,在匿名函数内通过 '$G' 函数(可能是自定义的获取 DOM 元素的函数)获取页面中 id 为 'J_resultBar' 的元素,并将其 'innerHTML' 属性设置为调用 '_renderTemplate' 方法(后续定义)处理后的歌曲列表数据(data.song_list),实现将获取到的音乐数据渲染并展示到页面相应区域的功能,延迟执行可能是为了等待页面其他相关元素加载或准备好,避免出现数据渲染的错误或不一致情况。 }, - dosearch:function () { + + dosearch: function () { var me = this; selectedItem = null; var key = $G('J_searchName').value; - if (utils.trim(key) == "")return false; + if (utils.trim(key) == "") return false; key = encodeURIComponent(key); me._sent(key); + // 定义 'dosearch' 方法,用于执行音乐搜索操作。首先将'selectedItem' 重置为 null,表示当前没有选中的歌曲。然后通过 '$G' 函数获取页面中 id 为 'J_searchName' 的输入框元素的值(用户输入的搜索关键词),并使用 'utils.trim' 函数(可能是自定义的去除字符串两端空白字符的函数)去除关键词两端的空白字符,如果处理后的关键词为空字符串,则直接返回 false,阻止搜索操作执行(因为没有有效的搜索内容)。如果关键词不为空,则使用 'encodeURIComponent' 函数对关键词进行 URL 编码,使其符合 URL 传参的格式要求,最后调用当前对象(通过'me' 引用)的 '_sent' 方法(后续定义),传入编码后的关键词,发起向服务器获取音乐数据的请求。 }, - doselect:function (i) { + + doselect: function (i) { var me = this; if (typeof i == 'object') { selectedItem = i; } else if (typeof i == 'number') { selectedItem = me.data[i]; } + // 定义 'doselect' 方法,用于处理用户选择音乐的操作。根据传入参数 'i' 的数据类型进行不同的处理,如果 'i' 是一个对象(可能是代表歌曲信息的对象),则直接将其赋值给'selectedItem',表示选中了这个歌曲对象;如果 'i' 是一个数字,则将当前对象(通过'me' 引用)的 'data' 属性(之前存储的歌曲列表数据)中对应索引的歌曲对象赋值给'selectedItem',这样就记录了用户选择的歌曲信息,方便后续进行播放、插入等相关操作。 }, - onpageclick:function (id) { + + onpageclick: function (id) { var me = this; for (var i = 0; i < pages.length; i++) { $G(pages[i]).className = 'pageoff'; @@ -54,8 +76,10 @@ function Music() { } $G('page' + id).className = 'pageon'; $G('panel' + id).className = 'panelon'; + // 定义 'onpageclick' 方法,用于处理分页点击事件。首先遍历 'pages' 和 'panels' 数组(之前存储了分页和面板相关元素的标识),通过 '$G' 函数获取对应的元素,并将它们的 'className' 属性分别设置为 'pageoff' 和 'paneloff',也就是将所有分页按钮和对应面板设置为未选中状态(关闭状态)。然后通过 '$G' 函数获取当前点击的分页按钮(根据传入的 'id' 参数拼接出对应的元素 ID,如 'page' + id),将其 'className' 属性设置为 'pageon'(选中状态),同时将对应的面板('panel' + id)的 'className' 设置为 'panelon'(显示状态),实现分页切换时相应页面内容显示和分页按钮状态切换的功能。 }, - listenTest:function (elem) { + + listenTest: function (elem) { var me = this, view = $G('J_preview'), is_play_action = (elem.className == 'm-try'), @@ -69,31 +93,39 @@ function Music() { elem.className = 'm-trying'; view.innerHTML = me._buildMusicHtml(me._getUrl(true)); } + // 定义 'listenTest' 方法,用于处理音乐试听相关操作。首先获取当前对象(通过'me' 引用)、页面中 id 为 'J_preview' 的元素(可能是用于音乐预览展示的区域),判断传入的元素(elem)的 'className' 是否为'm-try',如果是则将 'is_play_action' 设置为 true,表示是播放操作(从类名推测'm-try' 可能代表播放相关的样式类)。接着调用 '_getTryingElem' 方法(后续定义)获取之前正在试听的元素(如果存在的话),如果存在,则将其 'className' 恢复为'm-try'(表示停止播放状态),并清空 'J_preview' 元素的 'innerHTML'(清除之前的试听内容)。如果是播放操作('is_play_action' 为 true),则将传入元素(elem)的 'className' 修改为'm-trying'(可能代表正在播放的样式类),并通过调用 '_buildMusicHtml' 方法(后续定义)传入获取到的音乐播放 URL(通过 '_getUrl' 方法获取,且传入参数 true 表示是试听情况),将生成的包含音乐播放器的 HTML 代码设置为 'J_preview' 元素的 'innerHTML',实现在预览区域播放音乐的功能。 }, - _sent:function (param) { + + _sent: function (param) { var me = this; $G('J_resultBar').innerHTML = '
'; utils.loadFile(document, { - src:me.dataUrl + '&query=' + param + '&page_size=' + me.total + '&callback=music.callback&.r=' + Math.random(), - tag:"script", - type:"text/javascript", - defer:"defer" + src: me.dataUrl + '&query=' + param + '&page_size=' + me.total + '&callback=music.callback&.r=' + Math.random(), + tag: "script", + type: "text/javascript", + defer: "defer" }); + // 定义 '_sent' 方法,用于向服务器发送获取音乐数据的请求。首先通过 '$G' 函数获取页面中 id 为 'J_resultBar' 的元素,并将其 'innerHTML' 属性设置为一个包含 'loading' 类名的 div 元素(从类名推测用于展示加载提示信息,样式可能在外部 CSS 文件中定义),用于提示用户正在加载数据。然后使用 'utils.loadFile' 函数(可能是自定义的加载文件的函数,这里用于加载 JavaScript 脚本文件),向 'document' 对象(页面的文档对象)添加一个 script 标签,设置其'src' 属性为拼接好的请求 URL,包含了之前定义的 'dataUrl'(基础 API 地址)、搜索关键词参数(param)、每页显示数量(page_size)、回调函数名称(callback=music.callback,表示数据获取成功后调用 'Music' 类的 'callback' 方法)以及一个随机数(用于避免缓存,确保每次请求都是新的,.r= + Math.random()),同时设置标签的 'tag' 为 "script"(表示是脚本标签),'type' 为 "text/javascript"(脚本类型),'defer' 属性为 "defer"(表示延迟加载,即页面解析完后再执行脚本,避免阻塞页面渲染),通过这种方式向服务器发起获取音乐数据的请求,并在获取成功后通过指定的回调函数处理数据。 }, - _removeHtml:function (str) { + + _removeHtml: function (str) { var reg = /<\s*\/?\s*[^>]*\s*>/gi; return str.replace(reg, ""); + // 定义 '_removeHtml' 方法,用于去除字符串中的 HTML 标签。通过创建一个正则表达式对象(reg),匹配以 '<' 开头,中间包含任意字符(除了 '>'),以 '>' 结尾的 HTML 标签(包括自闭和标签以及成对标签),不区分大小写(gi 修饰符),然后使用字符串的'replace' 方法将匹配到的 HTML 标签替换为空字符串,返回处理后的字符串,可用于清理歌曲信息等文本中的 HTML 标签,获取纯文本内容,比如歌曲标题、歌手名等文本信息的提取和清理。 }, - _getUrl:function (isTryListen) { + + _getUrl: function (isTryListen) { var me = this; var param = 'from=tiebasongwidget&url=&name=' + encodeURIComponent(me._removeHtml(selectedItem.title)) + '&artist=' + encodeURIComponent(me._removeHtml(selectedItem.author)) + '&extra=' + encodeURIComponent(me._removeHtml(selectedItem.album_title)) - + '&autoPlay='+isTryListen+'' + '&loop=true'; - return me.playerUrl + "?" + param; + + '&autoPlay=' + isTryListen + '' + '&loop=true'; + return me.playerUrl + "?" + param; + // 定义 '_getUrl' 方法,用于获取音乐播放的 URL 参数。根据传入的 'isTryListen' 参数(布尔值,用于区分是试听还是正式插入播放等情况)构建请求参数 'param',参数中包含了来源信息(from=tiebasongwidget)、歌曲名称(通过获取'selectedItem' 的 'title' 属性,去除其中的 HTML 标签后进行 URL 编码)、歌手信息(同理处理 'author' 属性)、额外信息(可能是专辑相关,处理 'album_title' 属性)以及自动播放(autoPlay 根据 'isTryListen' 设置为 true 或 false)和循环播放(loop=true)等设置,最后将构建好的参数拼接在 'playerUrl'(音乐播放器的 Flash 文件 URL)后面,返回完整的音乐播放 URL,用于后续创建音乐播放相关的 HTML 元素或者发起播放请求等操作。 }, - _getTryingElem:function () { + + _getTryingElem: function () { var s = $G('J_listPanel').getElementsByTagName('span'); for (var i = 0; i < s.length; i++) { @@ -101,17 +133,22 @@ function Music() { return s[i]; } return null; + // 定义 '_getTryingElem' 方法,用于查找页面中正在试听的元素(通过样式类'm-trying' 判断)。首先通过 '$G' 函数获取页面中 id 为 'J_listPanel' 的元素,并获取其内部所有的'span' 标签元素,存储在's' 数组中。然后循环遍历这个数组,判断每个'span' 元素的 'className' 是否为'm-trying',如果找到符合条件的元素,则返回该元素,表示找到了正在试听的元素;如果循环结束都没有找到,则返回 null,说明当前没有正在试听的元素。 }, - _buildMusicHtml:function (playerUrl) { + + _buildMusicHtml: function (playerUrl) { var html = '' 嵌入元素,设置其类名为 'BDE_try_Music',禁止全屏(allowfullscreen="false"),指定 Flash 插件获取地址(pluginspage="http://www.macromedia.com/go/getflashplayer"),设置'src' 属性为传入的播放 URL,同时设置宽度和高度都为 1 像素,并通过样式将其定位到页面不可见的位置(left:-2000px,可能是为了在不需要显示播放器时隐藏它,又不影响页面布局),指定类型为 'application/x-shockwave-flash',设置透明模式(wmode="transparent")、自动播放(play="true")、不循环播放(loop="false")、隐藏菜单(menu="false")、禁止脚本访问(allowscriptaccess="never")以及无边框缩放(scale="noborder")等属性,最后返回构建好的 HTML 代码,可用于插入到页面中实现音乐播放功能(虽然设置了隐藏位置,但在合适的情况下可以调整位置使其可见并播放音乐)。 }, - _byteLength:function (str) { + + _byteLength: function (str) { return str.replace(/[^\u0000-\u007f]/g, "\u0061\u0061").length; + // 定义 '_byteLength' 方法,用于计算字符串的字节长度。通过正则表达式将字符串中非 }, _getMaxText:function (s) { var me = this; diff --git a/public2/ueditor/dialogs/preview/preview.html b/public2/ueditor/dialogs/preview/preview.html index f6b433b..63d0b7d 100644 --- a/public2/ueditor/dialogs/preview/preview.html +++ b/public2/ueditor/dialogs/preview/preview.html @@ -1,40 +1,56 @@ + "http://www.w3.org/TR/html4/loose.dtd"> - - - - - - - - -
+ /* 对 id 为 'preview' 的元素内部的所有子元素(通过通配符 * 选择)设置字体相关样式,将字体族(font-family)设置为无衬线字体(sans-serif),字体大小(font-size)设置为 16 像素,统一内部文本的字体显示风格 */ + + + + + + + + + + +
+ +
+ + + uParse('#preview', { + rootPath: '../../', + chartContainerHeight: 500 + }) + // 调用 'uParse' 函数(可能是在引入的 'ueditor.parse.js' 文件中定义的函数),传入两个参数,第一个参数是选择器 '#preview',表示要操作的目标元素是页面中 id 为 'preview' 的元素;第二个参数是一个对象,对象中设置了两个属性,'rootPath' 属性值为 '../../',可能用于指定一些资源文件(比如图片、样式表等相关文件)的根路径,方便后续在解析过程中正确加载相关依赖;'chartContainerHeight' 属性值为 500,可能是与图表展示相关的容器高度设置(如果有图表解析展示功能的话),整体这个函数调用可能用于对 'preview' 元素内部的内容进行特定的解析处理,使其能正确展示各种格式的内容(比如解析富文本中的图片、图表等元素)。 + + dialog.oncancel = function () { + document.getElementById('preview').innerHTML = ''; + } + // 将对话框(dialog,可能是页面上弹出的用于操作相关内容的对话框,具体实现依赖相关代码环境)的 'oncancel' 事件(通常表示用户点击了对话框中的“取消”按钮)绑定到一个匿名函数上,当用户点击“取消”按钮时,通过 document.getElementById 方法获取页面中 id 为 'preview' 的元素,并将其 innerHTML 属性设置为空字符串,也就是清空该元素内的内容,可能用于取消操作时清除之前在 'preview' 元素中展示的内容等情况。 + \ No newline at end of file diff --git a/public2/ueditor/dialogs/scrawl/scrawl.css b/public2/ueditor/dialogs/scrawl/scrawl.css index b18430d..8ec9c98 100644 --- a/public2/ueditor/dialogs/scrawl/scrawl.css +++ b/public2/ueditor/dialogs/scrawl/scrawl.css @@ -1,51 +1,205 @@ +css /*common +* 以下是通用样式部分的注释,这些样式通常会应用在页面多个元素上,用于设置一些基础的页面显示效果和元素外观风格。 */ -body{margin: 0;} -table{width:100%;} -table td{padding:2px 4px;vertical-align: middle;} -a{text-decoration: none;} -em{font-style: normal;} -.border_style1{border: 1px solid #ccc;border-radius: 5px;box-shadow:2px 2px 5px #d3d6da;} +body{ + margin: 0; + /* 将 body 元素的外边距设置为 0,去除页面默认的外边距,使页面内容能从浏览器视口边缘开始布局,方便进行整体的页面设计和元素定位 */ +} +table{ + width: 100%; + /* 设置表格元素的宽度为 100%,使其能占满父元素的宽度,常用于页面中需要自适应宽度的表格布局场景,确保表格能根据所在容器的宽度进行相应伸展 */ +} +table td{ + padding: 2px 4px; + vertical-align: middle; + /* 为表格中的单元格(td 元素)设置内边距,上下内边距为 2 像素,左右内边距为 4 像素,使单元格内的内容与边框之间有一定间隔;同时设置垂直对齐方式为居中(vertical-align: middle),让单元格内的内容(如文本、图片等)在垂直方向上处于中间位置,提升表格内容布局的美观度和可读性 */ +} +a{ + text-decoration: none; + /* 去除链接(a 元素)的默认下划线装饰效果,使链接文本在页面上显示更加简洁、美观,可根据实际设计需求通过其他方式(如颜色变化等)来体现链接的可点击性 */ +} +em{ + font-style: normal; + /* 将强调(em 元素)的默认斜体字体样式修改为正常字体样式,可能是为了统一文本显示风格,或者根据具体页面设计需要对 em 元素有不同的样式定义 */ +} +.border_style1{ + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 2px 2px 5px #d3d6da; + /* 定义一个名为 'border_style1' 的类选择器样式,用于添加具有特定边框效果的元素。设置边框为 1 像素宽的浅灰色(#ccc)实线,添加 5 像素的圆角效果(border-radius)使边框角变得圆润,增加页面元素的美观度;同时添加阴影效果(box-shadow),参数分别表示水平偏移、垂直偏移、模糊半径以及阴影颜色,营造出立体层次感,使元素在页面上更具立体感和视觉效果 */ +} + /*module +* 以下是模块相关样式部分的注释,这些样式主要针对页面中不同功能模块的元素进行样式设置,用于构建各个模块的特定布局和外观。 */ -.main{margin: 8px;overflow: hidden;} +.main{ + margin: 8px; + overflow: hidden; + /* 创建一个名为'main' 的类选择器样式,设置外边距为 8 像素,使该元素与周围元素间隔开一定距离;同时设置溢出内容隐藏(overflow: hidden),用于控制内部元素的显示范围,避免出现滚动条或者超出部分不显示等布局情况,常用于作为页面主要内容区域的容器样式设置 */ +} + +.hot{ + float: left; + height: 335px; + /* 将元素设置为左浮动(float: left),使其在父容器内靠左排列,常用于多列布局场景,让该元素与其他浮动元素或非浮动元素共同构成页面的布局结构;同时设置元素的高度为 335 像素,确定其在垂直方向上的尺寸大小 */ +} +.drawBoard{ + position: relative; + cursor: crosshair; + /* 设置元素的定位方式为相对定位(position: relative),相对定位的元素会相对于其原本在文档流中的位置进行定位调整,方便后续对其内部的绝对定位元素进行布局;同时将鼠标指针样式设置为十字线(cursor: crosshair),通常用于表示该区域可进行一些精准的绘制、选择等操作,从类名推测可能是与绘图相关的区域 */ +} +.brushBorad{ + position: absolute; + left: 0; + top: 0; + z-index: 998; + /* 设置元素的定位方式为绝对定位(position: absolute),绝对定位的元素会相对于最近的已定位祖先元素(如果没有则相对于 body 元素)进行定位,这里将其定位在父元素(可能是相对定位的容器)的左上角(left: 0,top: 0);设置 z-index 为 998,用于控制元素在页面中的堆叠顺序,数值越大越在上面,确保该元素在合适的层级显示,可能是绘图相关的画板之类的元素,需要显示在特定层级上 */ +} +.picBoard{ + border: none; + text-align: center; + line-height: 300px; + cursor: default; + /* 去除元素的边框(border: none);设置文本水平居中对齐(text-align: center),常用于包含图片等内容的元素,使其内部内容在水平方向上居中显示;设置行高为 300 像素(line-height: 300px),可用于垂直方向上的内容对齐或撑开元素高度等情况;将鼠标指针样式设置为默认指针(cursor: default),表示该区域没有特殊的交互操作提示 */ +} +.operateBar{ + margin-top: 10px; + font-size: 12px; + text-align: center; + /* 设置元素的上边距为 10 像素,使其与上方元素隔开一定距离;设置字体大小为 12 像素,调整文本显示大小;设置文本水平居中对齐(text-align: center),可能用于操作按钮、提示信息等元素的容器,使其内部元素在水平方向上居中排列,看起来更加规整 */ +} +.operateBar span{ + margin-left: 10px; + /* 为 'operateBar' 内部的 span 元素设置左边距为 10 像素,使 span 元素之间或与其他相邻元素在水平方向上隔开一定距离,常用于在一行内排列多个相关的文本或图标元素等情况 */ +} -.hot{float:left;height:335px;} -.drawBoard{position: relative; cursor: crosshair;} -.brushBorad{position: absolute;left:0;top:0;z-index: 998;} -.picBoard{border: none;text-align: center;line-height: 300px;cursor: default;} -.operateBar{margin-top:10px;font-size:12px;text-align: center;} -.operateBar span{margin-left: 10px;} +.drawToolbar{ + float: right; + width: 110px; + height: 300px; + overflow: hidden; + /* 将元素设置为右浮动(float: right),使其在父容器内靠右排列,与其他左浮动或非浮动元素共同构成多列布局;设置宽度为 110 像素,高度为 300 像素,确定其在水平和垂直方向上的尺寸大小;设置溢出内容隐藏(overflow: hidden),用于控制内部元素的显示范围,避免出现滚动条或者超出部分不显示等布局情况,可能是用于放置绘图工具相关的操作栏容器样式设置 */ +} +.colorBar{ + margin-top: 10px; + font-size: 12px; + text-align: center; + /* 设置元素的上边距为 10 像素,使其与上方元素隔开一定距离;设置字体大小为 12 像素,调整文本显示大小;设置文本水平居中对齐(text-align: center),可能是用于展示颜色选择相关元素的容器样式,使其内部的颜色块等元素在水平方向上居中排列 */ +} +.colorBar a{ + display: block; + width: 10px; + height: 10px; + border: 1px solid #1006F1; + border-radius: 3px; + box-shadow: 2px 2px 5px #d3d6da; + opacity: 0.3; + /* 将链接(a 元素)设置为块级元素显示(display: block),使其独占一行,方便进行样式布局和交互操作设置;设置宽度为 10 像素,高度为 10 像素,确定元素的尺寸大小,可能用于表示颜色小块;添加 1 像素宽的蓝色(#1006F1)边框,设置 3 像素的圆角效果,添加阴影效果,营造出立体层次感;设置透明度为 0.3(opacity: 0.3),使颜色块呈现出半透明效果,常用于颜色选择区域的颜色样本展示样式设置 */ +} +.sectionBar{ + margin-top: 15px; + font-size: 12px; + text-align: center; + /* 设置元素的上边距为 15 像素,使其与上方元素隔开一定距离;设置字体大小为 12 像素,调整文本显示大小;设置文本水平居中对齐(text-align: center),可能是用于展示与绘图相关的某个功能分区(从类名推测)元素的容器样式,使其内部相关元素在水平方向上居中排列 */ +} +.sectionBar a{ + display: inline-block; + width: 10px; + height: 12px; + color: #888; + text-indent: -999px; + opacity: 0.3; + /* 将链接(a 元素)设置为内联块级元素显示(display: inline-block),使其既具有块级元素可以设置宽高的特点,又能像内联元素一样在一行内排列;设置宽度为 10 像素,高度为 12 像素,确定元素的尺寸大小;设置文本颜色为灰色(#888),通过 text-indent: -999px 将文本缩进很大的距离,使其在页面上不显示出来(可能是通过背景图片等方式来展示相应的功能图标);设置透明度为 0.3,使其呈现半透明效果,可能用于表示不同功能选项的图标样式设置,通过不同的背景图片来区分不同功能 */ +} +.size1{ + background: url('images/size.png') 1px center no-repeat ; + /* 定义一个名为'size1' 的类选择器样式,设置背景图片为指定路径('images/size.png')下的图片文件,使其在元素内部从左边距 1 像素、垂直居中(center)的位置开始显示,且不重复平铺(no-repeat),从类名推测可能是用于表示某种绘图尺寸相关的图标样式,通过不同的背景图片位置来区分不同尺寸选项 */ +} +.size2{ + background: url('images/size.png') -10px center no-repeat; + /* 与'size1' 类似,也是设置背景图片为 'images/size.png',但图片显示位置从左边距 -10 像素、垂直居中的位置开始,用于表示另一种绘图尺寸相关的图标样式 */ +} +.size3{ + background: url('images/size.png') -22px center no-repeat; + /* 同样设置背景图片为 'images/size.png',图片显示位置从左边距 -22 像素、垂直居中的位置开始,作为又一种绘图尺寸相关的图标样式 */ +} +.size4{ + background: url('images/size.png') -35px center no-repeat; + /* 设置背景图片为 'images/size.png',图片显示位置从左边距 -35 像素、垂直居中的位置开始,用于区分不同的绘图尺寸相关图标样式 */ +} -.drawToolbar{float:right;width:110px;height:300px;overflow: hidden;} -.colorBar{margin-top:10px;font-size: 12px;text-align: center;} -.colorBar a{display:block;width: 10px;height: 10px;border:1px solid #1006F1;border-radius: 3px; box-shadow:2px 2px 5px #d3d6da;opacity: 0.3} -.sectionBar{margin-top:15px;font-size: 12px;text-align: center;} -.sectionBar a{display:inline-block;width:10px;height:12px;color: #888;text-indent: -999px;opacity: 0.3} -.size1{background: url('images/size.png') 1px center no-repeat ;} -.size2{background: url('images/size.png') -10px center no-repeat;} -.size3{background: url('images/size.png') -22px center no-repeat;} -.size4{background: url('images/size.png') -35px center no-repeat;} +.addImgH{ + position: relative; + /* 设置元素的定位方式为相对定位,为其内部的绝对定位元素提供定位基准,从类名推测可能是与添加图片相关的元素容器,后续可在这个相对定位的基础上进行更精确的元素布局 */ +} +.addImgH_form{ + position: absolute; + left: 18px; + top: -1px; + width: 75px; + height: 21px; + opacity: 0; + cursor: pointer; + /* 设置元素的定位方式为绝对定位,相对于最近的已定位祖先元素(这里就是相对定位的 'addImgH' 元素)定位到左边距 18 像素、上边距 -1 像素的位置;设置宽度为 75 像素,高度为 21 像素,确定元素的尺寸大小;设置透明度为 0(opacity: 0),使其初始状态为完全透明不可见,可能是用于隐藏实际的文件上传等表单元素,但又能通过设置为可点击(cursor: pointer)来触发添加图片的相关操作,通过一些交互逻辑使其在合适的时候变为可见状态 */ +} +.addImgH_form input{ + width: 100%; + /* 设置 'addImgH_form' 内部的 input 元素宽度为 100%,使其占满父元素的宽度,常用于表单输入框等元素,确保输入框能根据所在容器的宽度进行自适应伸展,方便用户输入相关信息 */ +} -.addImgH{position: relative;} -.addImgH_form{position: absolute;left: 18px;top: -1px;width: 75px;height: 21px;opacity: 0;cursor: pointer;} -.addImgH_form input{width: 100%;} /*scrawl遮罩层 +* 以下是关于涂鸦遮罩层相关样式部分的注释,用于设置遮罩层在页面上的显示效果、位置以及透明度等属性,以实现特定的视觉遮挡和提示功能。 */ -.maskLayerNull{display: none;} -.maskLayer{position: absolute;top:0;left:0;width: 100%; height: 100%;opacity: 0.7; - background-color: #fff;text-align:center;font-weight:bold;line-height:300px;z-index: 1000;} +.maskLayerNull{ + display: none; + /* 将元素设置为隐藏状态(display: none),不显示在页面上,从类名推测可能是在不需要遮罩层显示时应用的样式,用于控制遮罩层的显示隐藏逻辑 */ +} +.maskLayer{ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.7; + background-color: #fff; + text-align: center; + font-weight: bold; + line-height: 300px; + z-index: 1000; + /* 设置元素的定位方式为绝对定位,使其相对于 body 元素(因为没有更近的已定位祖先元素)定位到页面的左上角(top: 0,left: 0),并设置宽度和高度都为 100%,使其占满整个页面的可视区域;设置透明度为 0.7(opacity: 0.7),使其呈现半透明效果,背景颜色为白色(#fff),用于在页面上覆盖一层半透明的白色遮罩;设置文本水平居中对齐(text-align: center),字体加粗(font-weight: bold),行高为 300 像素(line-height: 300px),可能用于在遮罩层上显示一些提示信息等内容;设置 z-index 为 1000,确保遮罩层在页面的最上层显示,遮挡住下方的元素,起到遮罩提示的作用 */ +} + /*btn state +* 以下是按钮不同状态相关样式部分的注释,通过设置不同类名下的按钮元素样式,用于区分按钮在不同交互状态(如可点击、不可点击等)下的外观显示差异,如背景图片、文本颜色、鼠标指针样式等方面的变化。 */ -.previousStepH .icon{display: inline-block;width:16px;height:16px;background-image: url('images/undoH.png');cursor: pointer;} -.previousStepH .text{color:#888;cursor:pointer;} -.previousStep .icon{display: inline-block;width:16px;height:16px;background-image: url('images/undo.png');cursor:default;} -.previousStep .text{color:#ccc;cursor:default;} +.previousStepH.icon{ + display: inline-block; + width: 16px; + height: 16px; + background-image: url('images/undoH.png'); + cursor: pointer; + /* 将类名为 'previousStepH' 内部的 '.icon' 元素(可能是用于表示按钮图标部分的元素)设置为内联块级元素显示(display: inline-block),使其可以设置宽高且能在一行内排列;设置宽度为 16 像素,高度为 16 像素,确定元素的尺寸大小;设置背景图片为指定路径('images/undoH.png')下的图片文件,用于显示特定的图标;将鼠标指针样式设置为指针(cursor: pointer),表示该元素可点击,从类名推测可能是表示“上一步”操作按钮在可点击的高亮状态下的图标样式 */ +} +.previousStepH.text{ + color: #888; + cursor: pointer; + /* 将类名为 'previousStepH' 内部的 '.text' 元素(可能是用于表示按钮文本部分的元素)设置文本颜色为灰色(#888),将鼠标指针样式设置为指针(cursor: pointer),表示该部分文本所在的按钮整体在这个状态下是可点击的,与前面的图标部分共同构成“上一步”操作按钮在可点击高亮状态下的样式 */ +} +.previousStep.icon{ + display: inline-block; + width: 16px; + height: 16px; + background-image: url('images/undo.png'); + cursor: default; + /* 与 'previousStepH.icon' 类似,设置为内联块级元素显示,尺寸为 16 像素宽和 16 像素高,设置背景图片为 'images/undo.png',但将鼠标指针样式设置为默认指针(cursor: default),表示该元素不可点击,从类名推测可能是表示“上一步”操作按钮在不可点击的普通状态下的图标样式 */ +} +.previousStep.text{ + color: #ccc; + cursor: default; + /* 将类名为 'previousStep' 内部的 '.text' 元素设置文本颜色为更浅的灰色(#ccc),鼠标指针样式设置为默认指针(cursor: default),表示该部分文本所在的按钮整体在这个状态下是不可点击的,与前面的图标部分共同构成“上一步”操作按钮在不可点击普通状态下的样式 */ +} -.nextStepH .icon{display: inline-block;width:16px;height:16px;background-image: url('images/redoH.png');cursor: pointer;} -.nextStepH .text{color:#888;cursor:pointer;} -.nextStep .icon{display: inline-block;width:16px;height:16px;background-image: url('images/redo.png');cursor:default;} -.nextStep .text{color:#ccc;cursor:default;} .clearBoardH .icon{display: inline-block;width:16px;height:16px;background-image: url('images/emptyH.png');cursor: pointer;} .clearBoardH .text{color:#888;cursor:pointer;} diff --git a/public2/ueditor/dialogs/scrawl/scrawl.html b/public2/ueditor/dialogs/scrawl/scrawl.html index 9371abd..83229c2 100644 --- a/public2/ueditor/dialogs/scrawl/scrawl.html +++ b/public2/ueditor/dialogs/scrawl/scrawl.html @@ -2,94 +2,122 @@ - - + + + + + + + -
-
-
- -
-
-
- - - - - - - - - - - - - - - - -
-
-
-
-
- - 1 - 3 - 5 - 7 -
-
- - 1 - 3 - 5 - 7 -
-
-
- - -
- -
- +
+ +
+ +
+ + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + +
-
- - - - +
+ +
+ +
+ + 1 + 3 + 5 + 7 +
+ +
+ + 1 + 3 + 5 + 7 +
+ +
+
+ + +
+ +
+ +
+
+ +
+ + + + +
+
-
-
- +
+ + + \ No newline at end of file diff --git a/public2/ueditor/dialogs/scrawl/scrawl.js b/public2/ueditor/dialogs/scrawl/scrawl.js index d0b451b..aad07a8 100644 --- a/public2/ueditor/dialogs/scrawl/scrawl.js +++ b/public2/ueditor/dialogs/scrawl/scrawl.js @@ -1,74 +1,111 @@ -/** - * Created with JetBrains PhpStorm. - * User: xuheng - * Date: 12-5-22 - * Time: 上午11:38 - * To change this template use File | Settings | File Templates. - */ +// 创建一个名为 `scrawl` 的函数,它接受一个 `options` 参数,用于初始化绘图相关的配置选项。 +// 如果传入了 `options` 参数,会调用 `this.initOptions(options)` 方法来进行初始化操作,这是面向对象编程中常见的构造函数初始化逻辑。 var scrawl = function (options) { options && this.initOptions(options); }; + +// 立即执行函数,用于创建一些私有变量,并在 `scrawl` 函数的原型对象上定义一系列方法,实现绘图及相关操作的具体功能。 +// 这种方式可以将一些变量和逻辑封装在一个局部作用域内,避免全局变量污染,同时实现代码的模块化组织。 (function () { + // 获取页面中 id 为 `J_brushBoard` 的 `` 元素,它作为绘图的主要画布。 + // 通过 `getContext('2d')` 方法获取该画布的 2D 绘图上下文,用于后续进行图形绘制等操作。 + // 创建两个变量,`drawStep` 数组用于存储绘图操作的步骤数据(用于实现撤销、重做功能),`drawStepIndex` 用于记录当前操作步骤的索引位置,作为操作步骤的指针。 var canvas = $G("J_brushBoard"), context = canvas.getContext('2d'), - drawStep = [], //undo redo存储 - drawStepIndex = 0; //undo redo指针 + drawStep = [], //undo redo 存储 + drawStepIndex = 0; //undo redo 指针 + // 在 `scrawl` 函数的原型对象上定义一系列属性和方法,这些属性和方法会被 `scrawl` 类的实例所继承,用于实现绘图工具的各种功能,如绘图、操作按钮响应、颜色选择等。 scrawl.prototype = { - isScrawl:false, //是否涂鸦 - brushWidth:-1, //画笔粗细 - brushColor:"", //画笔颜色 - - initOptions:function (options) { + // `isScrawl` 属性用于标记是否正在进行涂鸦操作,初始值为 `false`。 + isScrawl: false, //是否涂鸦 + // `brushWidth` 属性用于记录画笔的粗细,初始值为 `-1`,后续会根据配置或用户选择进行更新。 + brushWidth: -1, //画笔粗细 + // `brushColor` 属性用于记录画笔的颜色,初始值为空字符串,同样会根据配置或操作进行相应设置。 + brushColor: "", //画笔颜色 + + // `initOptions` 方法用于初始化绘图工具的各种配置和事件监听器,接受一个 `options` 参数,包含了绘图相关的各种设置选项。 + initOptions: function (options) { var me = this; - me.originalState(options);//初始页面状态 - me._buildToolbarColor(options.colorList);//动态生成颜色选择集合 - - me._addBoardListener(options.saveNum);//添加画板处理 - me._addOPerateListener(options.saveNum);//添加undo redo clearBoard处理 - me._addColorBarListener();//添加颜色选择处理 - me._addBrushBarListener();//添加画笔大小处理 - me._addEraserBarListener();//添加橡皮大小处理 - me._addAddImgListener();//添加增添背景图片处理 - me._addRemoveImgListenter();//删除背景图片处理 - me._addScalePicListenter();//添加缩放处理 - me._addClearSelectionListenter();//添加清楚选中状态处理 - - me._originalColorSelect(options.drawBrushColor);//初始化颜色选中 - me._originalBrushSelect(options.drawBrushSize);//初始化画笔选中 - me._clearSelection();//清楚选中状态 + // 调用 `originalState` 方法,根据传入的 `options` 初始化页面的初始状态,如画笔大小、颜色等。 + me.originalState(options); + // 调用 `_buildToolbarColor` 方法,根据传入的颜色列表 `options.colorList` 动态生成颜色选择区域的 HTML 结构,并添加到页面中相应的元素内。 + me._buildToolbarColor(options.colorList); + + // 调用 `_addBoardListener` 方法,添加对画板的各种鼠标事件监听器,用于处理绘图操作,传入可撤销操作的次数 `options.saveNum`,用于控制操作记录相关逻辑。 + me._addBoardListener(options.saveNum); + // 调用 `_addOPerateListener` 方法,添加对操作按钮(如撤销、重做、清除画板等按钮)的点击事件监听器,传入 `options.saveNum`,用于相关操作的逻辑处理。 + me._addOPerateListener(options.saveNum); + // 调用 `_addColorBarListener` 方法,添加对颜色选择区域的点击事件监听器,用于处理用户选择颜色的操作。 + me._addColorBarListener(); + // 调用 `_addBrushBarListener` 方法,添加对画笔大小选择区域的点击事件监听器,用于处理用户选择画笔大小的操作。 + me._addBrushBarListener(); + // 调用 `_addEraserBarListener` 方法,添加对橡皮擦大小选择区域的点击事件监听器,用于处理用户选择橡皮擦大小的操作。 + me._addEraserBarListener(); + // 调用 `_addAddImgListener` 方法,添加对添加图片功能相关元素(如文件上传输入框)的事件监听器,用于处理添加背景图片的操作。 + me._addAddImgListener(); + // 调用 `_addRemoveImgListenter` 方法,添加对移除图片按钮的点击事件监听器,用于处理删除背景图片的操作。 + me._addRemoveImgListenter(); + // 调用 `_addScalePicListenter` 方法,添加对缩放图片按钮的点击事件监听器,用于处理图片缩放的操作。 + me._addScalePicListenter(); + // 调用 `_addClearSelectionListenter` 方法,添加对文档的鼠标移动事件监听器,用于清除选中状态,避免一些操作受选中内容的影响。 + me._addClearSelectionListenter(); + + // 调用 `_originalColorSelect` 方法,根据传入的初始画笔颜色 `options.drawBrushColor`,初始化颜色选择区域中对应颜色的选中状态显示。 + me._originalColorSelect(options.drawBrushColor); + // 调用 `_originalBrushSelect` 方法,根据传入的初始画笔大小 `options.drawBrushSize`,初始化画笔大小选择区域中对应大小的选中状态显示。 + me._originalBrushSelect(options.drawBrushSize); + // 调用 `_clearSelection` 方法,清除页面中一些元素的可选中状态,避免误操作等情况。 + me._clearSelection(); }, - originalState:function (options) { + // `originalState` 方法用于设置绘图的初始状态,根据传入的 `options` 参数来初始化画笔宽度、颜色以及画布的一些属性,如背景颜色、线条样式等。 + originalState: function (options) { var me = this; - me.brushWidth = options.drawBrushSize;//同步画笔粗细 - me.brushColor = options.drawBrushColor;//同步画笔颜色 - - context.lineWidth = me.brushWidth;//初始画笔大小 - context.strokeStyle = me.brushColor;//初始画笔颜色 - context.fillStyle = "transparent";//初始画布背景颜色 - context.lineCap = "round";//去除锯齿 + // 将当前对象的 `brushWidth` 属性设置为传入的 `options` 中的 `drawBrushSize` 值,实现画笔粗细的同步设置。 + me.brushWidth = options.drawBrushSize; + // 将当前对象的 `brushColor` 属性设置为传入的 `options` 中的 `drawBrushColor` 值,实现画笔颜色的同步设置。 + me.brushColor = options.drawBrushColor; + + // 设置绘图上下文的线条宽度为当前对象的 `brushWidth` 值,确定初始画笔大小。 + context.lineWidth = me.brushWidth; + // 设置绘图上下文的线条颜色为当前对象的 `brushColor` 值,确定初始画笔颜色。 + context.strokeStyle = me.brushColor; + // 设置绘图上下文的填充颜色为透明("transparent"),即画布初始背景为透明,可能后续会根据具体绘制情况进行填充或覆盖等操作。 + context.fillStyle = "transparent"; + // 设置绘图上下文的线条端点样式为圆形("round"),用于去除绘制线条时的锯齿效果,使线条看起来更平滑。 + context.lineCap = "round"; + // 执行填充操作,由于填充颜色为透明,这里实际不会有可见的填充效果,但可能是为了确保一些默认设置生效或者后续有相关逻辑基于此操作。 context.fill(); }, - _buildToolbarColor:function (colorList) { + + // `_buildToolbarColor` 方法用于动态生成颜色选择区域的 HTML 结构,根据传入的颜色列表 `colorList` 创建一个表格形式的颜色块展示区域,并将其添加到页面中 id 为 `J_colorBar` 的元素内。 + _buildToolbarColor: function (colorList) { var tmp = null, arr = []; + // 创建一个表格开始标签,并将其添加到 `arr` 数组中,用于构建颜色选择区域的整体 HTML 结构。 arr.push(""); + // 循环遍历传入的 `colorList` 数组,每个元素代表一种颜色代码。 for (var i = 0, color; color = colorList[i++];) { + // 每 5 个颜色块为一行,当是新的一行开头(索引减 1 后能被 5 整除且不是第一个颜色块时),添加一个表格行结束标签,并添加一个新的表格行开始标签。 if ((i - 1) % 5 == 0) { - if (i != 1) { + if (i!= 1) { arr.push(""); } arr.push(""); } + // 将颜色代码转换为完整的颜色值格式(添加 `#` 前缀),并创建一个包含该颜色作为背景色的 `` 元素,用于表示一个颜色块,添加到 `arr` 数组中。 tmp = '#' + color; arr.push(""); } + // 添加表格行结束标签和表格结束标签,完成整个表格结构的构建。 arr.push("
"); + // 将构建好的 HTML 结构通过设置页面中 `J_colorBar` 元素的 `innerHTML` 属性添加到页面中,实现颜色选择区域的展示。 $G("J_colorBar").innerHTML = arr.join(""); }, - _addBoardListener:function (saveNum) { + // `_addBoardListener` 方法用于添加对画板(`` 元素)的鼠标事件监听器,处理鼠标按下、移动、抬起和移出等操作,实现绘图功能以及操作步骤的记录,用于撤销、重做等功能实现。 + _addBoardListener: function (saveNum) { var me = this, margin = 0, startX = -1, @@ -78,12 +115,15 @@ var scrawl = function (options) { isMouseUp = false, buttonPress = 0, button, flag = ''; + // 获取页面中 `J_wrap` 元素的左边距值(通过 `getComputedStyle` 方法获取计算后的样式属性值,并将其转换为整数类型),用于后续计算鼠标在画布上的实际坐标,考虑到元素的外边距等布局因素。 margin = parseInt(domUtils.getComputedStyle($G("J_wrap"), "margin-left")); + // 将当前画布的初始图像数据(通过 `getImageData` 方法获取整个画布的像素数据)添加到 `drawStep` 数组中,作为操作步骤记录的起始状态,同时将 `drawStepIndex` 加 1,表示操作步骤索引前进一位。 drawStep.push(context.getImageData(0, 0, context.canvas.width, context.canvas.height)); drawStepIndex += 1; + // 使用 `domUtils`(可能是自定义的 DOM 操作工具对象,包含处理 DOM 事件绑定等功能的函数)的 `on` 方法,为 `canvas` 元素绑定多个鼠标事件("mousedown"、"mousemove"、"mouseup"、"mouseout")的监听器,在事件回调函数中根据不同的鼠标事件类型进行相应的绘图和操作记录处理。 domUtils.on(canvas, ["mousedown", "mousemove", "mouseup", "mouseout"], function (e) { - button = browser.webkit ? e.which : buttonPress; + button = browser.webkit? e.which : buttonPress; switch (e.type) { case 'mousedown': buttonPress = 1; @@ -92,21 +132,23 @@ var scrawl = function (options) { isMouseUp = false; isMouseMove = false; me.isScrawl = true; - startX = e.clientX - margin;//10为外边距总和 + startX = e.clientX - margin; startY = e.clientY - margin; context.beginPath(); break; - case 'mousemove' : + // 当鼠标按下时,记录鼠标按钮状态,设置相关操作标记为 `true`,标记当前正在进行涂鸦操作,计算鼠标在画布上的起始坐标(考虑外边距因素),并开始一个新的绘图路径,为后续绘制线条做准备。 + + case 'mousemove': if (!flag && button == 0) { return; } if (!flag && button) { - startX = e.clientX - margin;//10为外边距总和 + startX = e.clientX - margin; startY = e.clientY - margin; context.beginPath(); flag = 1; } - if (isMouseUp || !isMouseDown) { + if (isMouseUp ||!isMouseDown) { return; } var endX = e.clientX - margin, @@ -119,9 +161,12 @@ var scrawl = function (options) { startY = endY; isMouseMove = true; break; + // 当鼠标移动时,如果不符合某些条件(如未开始绘图或者鼠标按钮未按下等情况)则直接返回不做处理。 + // 如果是正常的绘图移动操作,计算鼠标当前位置坐标,将绘图路径移动到起始坐标位置,然后绘制一条从起始坐标到当前坐标的线条,并更新起始坐标为当前坐标,标记当前正在进行鼠标移动操作,用于后续判断是否绘制连续线条等情况。 + case 'mouseup': buttonPress = 0; - if (!isMouseDown)return; + if (!isMouseDown) return; if (!isMouseMove) { context.arc(startX, startY, context.lineWidth, 0, Math.PI * 2, false); context.fillStyle = context.strokeStyle; @@ -135,17 +180,25 @@ var scrawl = function (options) { startX = -1; startY = -1; break; + // 当鼠标抬起时,重置鼠标按钮状态,如果未进行过鼠标按下操作则直接返回。 + // 如果鼠标按下后没有移动过(即只是点击操作),则在点击位置绘制一个填充的圆形(根据画笔宽度作为半径),填充颜色与画笔颜色相同。 + // 关闭当前绘图路径,调用 `_saveOPerate` 方法保存当前操作步骤(传入可撤销操作次数 `saveNum`),重置相关操作标记和起始坐标,完成一次绘图操作的记录。 + case 'mouseout': flag = ''; buttonPress = 0; if (button == 1) return; context.closePath(); break; + // 当鼠标移出画布区域时,重置相关操作标记和鼠标按钮状态,如果鼠标右键按下则直接返回,关闭当前绘图路径,避免出现一些异常的绘图状态。 } }); }, - _addOPerateListener:function (saveNum) { + + // `_addOPerateListener` 方法用于添加对操作按钮(如撤销、重做、清除画板等按钮)的点击事件监听器,根据不同按钮的点击操作执行相应的绘图状态修改、操作步骤处理等功能。 + _addOPerateListener: function (saveNum) { var me = this; + // 为页面中 id 为 `J_previousStep` 的元素(可能是“上一步”操作按钮)添加点击事件监听器,当点击该按钮时,执行撤销操作相关的逻辑。 domUtils.on($G("J_previousStep"), "click", function () { if (drawStepIndex > 1) { drawStepIndex -= 1; @@ -155,6 +208,9 @@ var scrawl = function (options) { drawStepIndex == 1 && me.btn2disable("J_previousStep"); } }); + // 如果当前操作步骤索引大于 1(表示有可撤销的操作步骤),则将操作步骤索引减 1,清空整个画布内容(通过 `clearRect` 方法),然后将上一步的图像数据(通过 `putImageData` 方法)绘制到画布上,实现撤销操作;同时将“下一步”按钮设置为可点击状态(通过 `btn2Highlight` 方法),如果操作步骤索引回到了 1,则将“上一步”按钮设置为不可点击状态(通过 `btn2disable` 方法)。 + + // 为页面中 id 为 `J_nextStep` 的元素(可能是“下一步”操作按钮)添加点击事件监听器,当点击该按钮时,执行重做操作相关的逻辑。 domUtils.on($G("J_nextStep"), "click", function () { if (drawStepIndex > 0 && drawStepIndex < drawStep.length) { context.clearRect(0, 0, context.canvas.width, context.canvas.height); @@ -164,6 +220,9 @@ var scrawl = function (options) { drawStepIndex == drawStep.length && me.btn2disable("J_nextStep"); } }); + // 如果当前操作步骤索引大于 0 且小于总操作步骤数(表示有可重做的操作步骤),则清空整个画布内容,将当前步骤对应的图像数据绘制到画布上,实现重做操作;同时将“上一步”按钮设置为可点击状态,当操作步骤索引达到总步骤数时,将“下一步”按钮设置为不可点击状态。 + + // 为页面中 id 为 `J_clearBoard` 的元素(可能是“清除画板”操作按钮)添加点击事件监听器,当点击该按钮时,执行清除画板的操作以及相关的状态重置逻辑。 domUtils.on($G("J_clearBoard"), "click", function () { context.clearRect(0, 0, context.canvas.width, context.canvas.height); drawStep = []; diff --git a/public2/ueditor/dialogs/searchreplace/searchreplace.html b/public2/ueditor/dialogs/searchreplace/searchreplace.html index b91f190..49315a9 100644 --- a/public2/ueditor/dialogs/searchreplace/searchreplace.html +++ b/public2/ueditor/dialogs/searchreplace/searchreplace.html @@ -1,102 +1,160 @@ + "http://www.w3.org/TR/html4/loose.dtd"> - + + + + -
- -
-
- - - - - - - - - - - - - - - - - - - - - - -
:
- -
- - -
-   -
- -
+
+ + -
- - - - - - - +
+ +
+ +
:
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
:
+ +
+ + +
+   +
+ +
+
+
+ + + + + + + + - - - - - - - - - - - - - - - - - - -
:
:
- -
- - - - -
-   -
- -
+ + + + : + + + + + + + + + + + + + + + + + + + + + +   + + + + + + + + + + +
-
- + + \ No newline at end of file diff --git a/public2/ueditor/dialogs/searchreplace/searchreplace.js b/public2/ueditor/dialogs/searchreplace/searchreplace.js index 02fa46c..8e3faed 100644 --- a/public2/ueditor/dialogs/searchreplace/searchreplace.js +++ b/public2/ueditor/dialogs/searchreplace/searchreplace.js @@ -6,119 +6,149 @@ * To change this template use File | Settings | File Templates. */ -//清空上次查选的痕迹 +// 清空上次查找选择的痕迹相关变量设置 +// 将 `editor` 对象(可能是整个编辑器相关的全局对象,包含了编辑器的各种状态和操作方法等)的 `firstForSR` 属性设置为 0,这个属性可能用于记录查找操作的起始相关状态,重置为初始值表示清除上次查找的起始相关痕迹。 +// 将 `editor` 对象的 `currentRangeForSR` 属性设置为 `null`,该属性可能用于记录当前查找操作涉及的文本范围相关信息,设置为 `null` 即清除上次查找操作对应的文本范围记录。 editor.firstForSR = 0; editor.currentRangeForSR = null; -//给tab注册切换事件 -/** - * tab点击处理事件 - * @param tabHeads - * @param tabBodys - * @param obj - */ -function clickHandler( tabHeads,tabBodys,obj ) { - //head样式更改 - for ( var k = 0, len = tabHeads.length; k < len; k++ ) { + +// 给选项卡(tab)注册切换事件相关的函数定义及逻辑实现部分 + +// `clickHandler` 函数用于处理选项卡头部标签的点击事件,实现切换选项卡时的样式更改以及对应内容面板的显示隐藏切换功能。 +// 接受三个参数:`tabHeads` 是包含所有选项卡头部标签元素的数组,`tabBodys` 是包含所有对应内容面板元素的数组,`obj` 是当前被点击的选项卡头部标签元素。 +function clickHandler(tabHeads, tabBodys, obj) { + // 遍历所有的选项卡头部标签元素,将它们的类名(className)清空,用于去除之前可能存在的表示选中状态等的类样式,为重新设置选中样式做准备。 + for (var k = 0, len = tabHeads.length; k < len; k++) { tabHeads[k].className = ""; } + // 将当前被点击的选项卡头部标签元素(`obj`)设置为 'focus' 类名,通过 CSS 中对 'focus' 类的样式定义(可能是设置不同的背景色、字体颜色等样式来突出显示当前选中的选项卡)来体现当前选项卡处于选中状态。 obj.className = "focus"; - //body显隐 - var tabSrc = obj.getAttribute( "tabSrc" ); - for ( var j = 0, length = tabBodys.length; j < length; j++ ) { + + // 处理选项卡对应内容面板的显示隐藏切换逻辑。 + var tabSrc = obj.getAttribute("tabSrc"); + for (var j = 0, length = tabBodys.length; j < length; j++) { var body = tabBodys[j], - id = body.getAttribute( "id" ); - if ( id != tabSrc ) { + id = body.getAttribute("id"); + // 如果当前内容面板的 `id` 与被点击选项卡头部标签元素的 `tabSrc` 属性值不相等,说明不是当前要显示的面板,则将其 `z-index` 设置为 1(通过 `z-index` 控制元素在页面中的堆叠顺序,较低的值表示在更下层,可能会被上层元素遮挡),使其处于隐藏或者靠后的显示层级。 + if (id!= tabSrc) { body.style.zIndex = 1; } else { + // 如果 `id` 与 `tabSrc` 属性值相等,说明是当前要显示的面板,则将其 `z-index` 设置为 200,使其处于较高的显示层级,显示在最上层,实现显示当前选中选项卡对应的内容面板,隐藏其他面板的效果。 body.style.zIndex = 200; } } - } -/** - * TAB切换 - * @param tabParentId tab的父节点ID或者对象本身 - */ -function switchTab( tabParentId ) { - var tabElements = $G( tabParentId ).children, +// `switchTab` 函数用于实现整个选项卡切换的功能,通过查找页面中指定 `tabParentId` 对应的父元素及其子元素,为每个选项卡头部标签添加点击事件监听器,在点击时调用 `clickHandler` 函数来完成切换操作。 +// 接受一个参数 `tabParentId`,它可以是选项卡的父节点的 `ID`,也可以直接是选项卡所在的父节点对象本身,用于定位到包含选项卡头部和内容面板的父元素。 +function switchTab(tabParentId) { + // 通过 `$G` 函数(可能是自定义的用于获取页面元素的函数,根据传入的 `ID` 或者对象本身来获取对应的 DOM 元素)获取指定 `tabParentId` 的子元素数组,假设第一个子元素包含选项卡头部标签,第二个子元素包含对应的内容面板元素。 + var tabElements = $G(tabParentId).children, tabHeads = tabElements[0].children, tabBodys = tabElements[1].children; - for ( var i = 0, length = tabHeads.length; i < length; i++ ) { + for (var i = 0, length = tabHeads.length; i < length; i++) { var head = tabHeads[i]; - if ( head.className === "focus" )clickHandler(tabHeads,tabBodys, head ); + // 如果当前选项卡头部标签已经有 'focus' 类名(表示当前处于选中状态),则直接调用 `clickHandler` 函数进行一次初始化的切换操作设置,确保页面加载时当前选中的选项卡对应的样式和面板显示是正确的。 + if (head.className === "focus") clickHandler(tabHeads, tabBodys, head); + // 为每个选项卡头部标签添加点击事件监听器,当点击某个选项卡头部标签时,调用 `clickHandler` 函数,并传入对应的 `tabHeads`、`tabBodys` 和当前点击的标签元素(`this`)作为参数,实现选项卡的切换操作逻辑。 head.onclick = function () { - clickHandler(tabHeads,tabBodys,this); + clickHandler(tabHeads, tabBodys, this); } } } -$G('searchtab').onmousedown = function(){ + +// 为页面中 `id` 为 `searchtab` 的元素添加鼠标按下事件监听器,当在该元素上按下鼠标时,清空页面中 `id` 为 `search-msg` 和 `replace-msg` 的元素的内容(innerHTML)。 +// 推测 `search-msg` 和 `replace-msg` 元素是用于显示查找和替换操作相关提示信息的区域,通过清空它们的内容,实现清除之前可能存在的提示信息,为下一次操作显示新的提示做准备。 +$G('searchtab').onmousedown = function () { $G('search-msg').innerHTML = ''; $G('replace-msg').innerHTML = '' } -//是否区分大小写 + +// `getMatchCase` 函数用于获取指定 `id` 对应的复选框元素的选中状态,返回一个布尔值,表示是否选中。 +// 接受一个参数 `id`,即要获取选中状态的复选框元素的 `ID`,通过 `$G` 函数获取该元素,然后判断其 `checked` 属性(复选框的选中状态属性,`true` 表示选中,`false` 表示未选中),并返回对应的布尔值。 function getMatchCase(id) { - return $G(id).checked ? true : false; + return $G(id).checked? true : false; } -//查找 + +// 以下是各个操作按钮的点击事件处理函数,分别对应不同的查找、替换操作逻辑 + +// “下一个查找”按钮(`id` 为 `nextFindBtn`)的点击事件处理函数 +// 点击该按钮时,获取页面中 `id` 为 `findtxt` 的输入框中的值作为要查找的字符串,如果该值为空(即用户未输入查找内容),则直接返回 `false`,不执行后续查找操作。 +// 然后创建一个包含查找字符串、查找方向(这里设置为 1,可能表示正向查找,具体含义依赖业务逻辑定义)以及是否区分大小写(通过调用 `getMatchCase` 函数获取 `matchCase` 复选框的选中状态来确定)等信息的对象 `obj`,并将其作为参数传递给 `frCommond` 函数来执行实际的查找操作。 +// 如果 `frCommond` 函数返回 `false`(表示查找失败或者未找到匹配内容等情况),则创建一个书签(bookmark,可能用于记录当前文本选择的位置信息,方便后续恢复位置等操作),在页面中 `id` 为 `search-msg` 的元素内显示 `lang.getEnd`(可能是预定义的表示查找结束等相关提示信息的字符串,具体内容依赖语言配置等情况),并将文本选择范围移动到书签位置并选中该范围(可能用于突出显示查找的起始位置等情况)。 $G("nextFindBtn").onclick = function (txt, dir, mcase) { var findtxt = $G("findtxt").value, obj; if (!findtxt) { return false; } obj = { - searchStr:findtxt, - dir:1, - casesensitive:getMatchCase("matchCase") + searchStr: findtxt, + dir: 1, + casesensitive: getMatchCase("matchCase") }; if (!frCommond(obj)) { var bk = editor.selection.getRange().createBookmark(); $G('search-msg').innerHTML = lang.getEnd; editor.selection.getRange().moveToBookmark(bk).select(); - - } }; + +// “下一个替换”按钮(`id` 为 `nextReplaceBtn`)的点击事件处理函数 +// 点击该按钮时,获取页面中 `id` 为 `findtxt1` 的输入框中的值作为要查找的字符串,如果该值为空则返回 `false`,不执行后续操作。 +// 创建一个包含查找字符串、查找方向(设置为 1,可能表示正向查找)以及是否区分大小写(通过 `getMatchCase` 函数获取 `matchCase1` 复选框的选中状态确定)等信息的对象 `obj`,并传递给 `frCommond` 函数执行实际的替换相关操作(具体替换逻辑在 `frCommond` 函数内部或者依赖其调用的其他函数实现)。 $G("nextReplaceBtn").onclick = function (txt, dir, mcase) { var findtxt = $G("findtxt1").value, obj; if (!findtxt) { return false; } obj = { - searchStr:findtxt, - dir:1, - casesensitive:getMatchCase("matchCase1") + searchStr: findtxt, + dir: 1, + casesensitive: getMatchCase("matchCase1") }; frCommond(obj); }; + +// “上一个查找”按钮(`id` 为 `preFindBtn`)的点击事件处理函数 +// 与“下一个查找”按钮逻辑类似,获取 `findtxt` 输入框的值作为查找字符串,为空则返回 `false`。 +// 创建包含查找字符串、查找方向(设置为 -1,可能表示反向查找)以及是否区分大小写信息的对象 `obj`,传递给 `frCommond` 函数执行查找操作,如果查找失败(`frCommond` 函数返回 `false`),则在 `search-msg` 元素内显示 `lang.getStart`(可能是表示查找起始等相关提示信息的字符串)。 $G("preFindBtn").onclick = function (txt, dir, mcase) { var findtxt = $G("findtxt").value, obj; if (!findtxt) { return false; } obj = { - searchStr:findtxt, - dir:-1, - casesensitive:getMatchCase("matchCase") + searchStr: findtxt, + dir: -1, + casesensitive: getMatchCase("matchCase") }; if (!frCommond(obj)) { $G('search-msg').innerHTML = lang.getStart; } -}; +} + +// “上一个替换”按钮(`id` 为 `preReplaceBtn`)的点击事件处理函数 +// 类似“下一个替换”按钮逻辑,获取 `findtxt1` 输入框的值作为查找字符串,为空则返回 `false`,创建相应对象并传递给 `frCommond` 函数执行替换相关操作。 $G("preReplaceBtn").onclick = function (txt, dir, mcase) { var findtxt = $G("findtxt1").value, obj; if (!findtxt) { return false; } obj = { - searchStr:findtxt, - dir:-1, - casesensitive:getMatchCase("matchCase1") + searchStr: findtxt, + dir: -1, + casesensitive: getMatchCase("matchCase1") }; frCommond(obj); -}; -//替换 +} + +// “替换”按钮(`id` 为 `repalceBtn`)的点击事件处理函数 +// 点击该按钮时,首先触发编辑器(`editor`)的 `clearLastSearchResult` 事件(可能用于清除上次查找替换操作留下的一些结果相关状态,比如之前选中的文本范围等,确保本次操作不受上次影响)。 +// 获取 `findtxt1` 和 `replacetxt` 输入框的值,分别作为要查找和替换成的字符串,并去除字符串两端的空白字符(通过正则表达式 `/^\s|\s$/g` 进行匹配替换)。 +// 如果要查找的字符串为空则返回 `false`,不执行替换操作。 +// 接着判断要查找和替换的字符串是否相等(包括不区分大小写情况下相等,通过 `toLowerCase` 方法将字符串转换为小写后进行比较),如果相等也返回 `false`,不进行无意义的替换操作。 +// 最后创建一个包含查找字符串、查找方向(设置为 1)、是否区分大小写以及替换字符串等信息的对象 `obj`,并传递给 `frCommond` 函数执行实际的替换操作。 $G("repalceBtn").onclick = function () { editor.trigger('clearLastSearchResult'); var findtxt = $G("findtxt1").value.replace(/^\s|\s$/g, ""), obj, @@ -130,14 +160,18 @@ $G("repalceBtn").onclick = function () { return false; } obj = { - searchStr:findtxt, - dir:1, - casesensitive:getMatchCase("matchCase1"), - replaceStr:replacetxt + searchStr: findtxt, + dir: 1, + casesensitive: getMatchCase("matchCase1"), + replaceStr: replacetxt }; frCommond(obj); -}; -//全部替换 +} + +// “全部替换”按钮(`id` 为 `repalceAllBtn`)的点击事件处理函数 +// 与“替换”按钮类似,获取 `findtxt1` 和 `replacetxt` 输入框的值并去除两端空白字符,为空则返回 `false`,判断两者相等情况(包括不区分大小写相等情况),相等则返回 `false`,不执行操作。 +// 创建一个包含查找字符串、是否区分大小写、替换字符串以及 `all` 属性设置为 `true`(表示执行全部替换操作,区别于单个替换)的对象 `obj`,传递给 `frCommond` 函数执行全部替换操作,获取返回的替换次数 `num`(如果替换成功,`frCommond` 函数可能返回替换的次数)。 +// 如果 `num` 有值(即替换次数大于 0,表示有进行替换操作),则在页面中 `replace-msg` 元素内显示替换次数相关的提示信息,通过 `lang.countMsg.replace` 方法(可能是根据预定义的字符串模板,将其中的 `{#count}` 占位符替换为实际的替换次数 `num`)来生成具体的提示内容,向用户展示替换的结果情况。 $G("repalceAllBtn").onclick = function () { var findtxt = $G("findtxt1").value.replace(/^\s|\s$/g, ""), obj, replacetxt = $G("replacetxt").value.replace(/^\s|\s$/g, ""); @@ -148,23 +182,26 @@ $G("repalceAllBtn").onclick = function () { return false; } obj = { - searchStr:findtxt, - casesensitive:getMatchCase("matchCase1"), - replaceStr:replacetxt, - all:true + searchStr: findtxt, + casesensitive: getMatchCase("matchCase1"), + replaceStr: replacetxt, + all: true }; var num = frCommond(obj); if (num) { $G('replace-msg').innerHTML = lang.countMsg.replace("{#count}", num); } -}; -//执行 +} + +// `frCommond` 函数用于执行实际的查找替换命令,它接受一个对象参数 `obj`(包含查找替换相关的各种信息,如查找字符串、替换字符串、是否区分大小写、查找方向等),并调用 `editor` 对象的 `execCommand` 方法(可能是编辑器提供的用于执行各种命令操作的接口函数),传入 `searchreplace` 命令和 `obj` 参数,将实际的查找替换操作转发给编辑器内部进行处理,最后返回 `execCommand` 方法的执行结果,用于判断操作是否成功等情况。 var frCommond = function (obj) { return editor.execCommand("searchreplace", obj); }; -switchTab("searchtab"); +// 调用 `switchTab` 函数,传入 `searchtab`(可能是包含搜索和替换选项卡的父元素的 `ID`),启动选项卡切换功能的初始化设置,确保页面加载时选项卡的初始状态和切换逻辑正常工作。 +switchTab("searchtab"); -dialog.onclose = function(){ +// 为对话框(`dialog`,可能是与查找替换操作相关的弹出式对话框,用于显示一些提示信息、操作确认等功能)的关闭事件(`onclose`)添加监听器,当对话框关闭时,触发编辑器的 `clearLastSearchResult` 事件,用于清除查找替换操作相关的一些遗留状态,保证下次操作的初始状态正确。 +dialog.onclose = function () { editor.trigger('clearLastSearchResult') }; \ No newline at end of file diff --git a/public2/ueditor/dialogs/snapscreen/snapscreen.html b/public2/ueditor/dialogs/snapscreen/snapscreen.html index cf8209e..f1d276b 100644 --- a/public2/ueditor/dialogs/snapscreen/snapscreen.html +++ b/public2/ueditor/dialogs/snapscreen/snapscreen.html @@ -1,58 +1,120 @@ - - - - - - - -
-

-
-
-
-
-
-
- + + dt a:hover { + /* 鼠标悬停时的背景颜色设置为#e0e0e0 */ + background: #e0e0e0; + /* 鼠标悬停时的边框颜色设置为#999 */ + border-color: #999 + } + + dt a:active { + /* 鼠标点击激活时的背景颜色设置为#ccc */ + background: #ccc; + /* 鼠标点击激活时的边框颜色设置为#999 */ + border-color: #999; + /* 鼠标点击激活时的文字颜色设置为#666 */ + color: #666; + } + + dd { + /* 设置行高为20px,并且距离上方元素有10px的外边距 */ + line-height: 20px; + margin-top: 10px; + } + + span { + /* 设置右边内边距为4px */ + padding-right: 4px; + } + + input { + /* 设置输入框宽度为210px,高度为21px,背景颜色为白色,边框为1px的实线,颜色为#d7d7d7,内外边距都设置为0 */ + width: 210px; + height: 21px; + background: #FFF; + border: 1px solid #d7d7d7; + padding: 0px; + margin: 0px; + } + + + +
+ +

+
+ +
+ +
+ +
+
+
+ \ No newline at end of file diff --git a/public2/ueditor/dialogs/spechars/spechars.html b/public2/ueditor/dialogs/spechars/spechars.html index 0b5c416..73097d6 100644 --- a/public2/ueditor/dialogs/spechars/spechars.html +++ b/public2/ueditor/dialogs/spechars/spechars.html @@ -1,21 +1,49 @@ + "http://www.w3.org/TR/html4/loose.dtd"> + + - + + + +
+
- + + \ No newline at end of file diff --git a/public2/ueditor/dialogs/spechars/spechars.js b/public2/ueditor/dialogs/spechars/spechars.js index f4c155e..ed30c86 100644 --- a/public2/ueditor/dialogs/spechars/spechars.js +++ b/public2/ueditor/dialogs/spechars/spechars.js @@ -4,8 +4,11 @@ * Date: 12-9-26 * Time: 下午1:09 * To change this template use File | Settings | File Templates. + * 上面这部分是代码的文件头注释,通常由开发工具自动生成,包含了创建文件所使用的编辑器(JetBrains PhpStorm)、作者(xuheng)、创建日期以及关于修改模板相关的提示信息等,主要用于代码的溯源和基本信息记录 */ +// 定义一个名为charsContent的数组,数组中每个元素都是一个对象,用于存储不同类型的字符相关信息 var charsContent = [ + // 第一个对象,代表一种字符类型(这里可能是特殊符号之类的,从包含的字符推测),有name、title、content三个属性 { name:"tsfh", title:lang.tsfh, content:toArray("、,。,·,ˉ,ˇ,¨,〃,々,—,~,‖,…,‘,’,“,”,〔,〕,〈,〉,《,》,「,」,『,』,〖,〗,【,】,±,×,÷,∶,∧,∨,∑,∏,∪,∩,∈,∷,√,⊥,∥,∠,⌒,⊙,∫,∮,≡,≌,≈,∽,∝,≠,≮,≯,≤,≥,∞,∵,∴,♂,♀,°,′,″,℃,$,¤,¢,£,‰,§,№,☆,★,○,●,◎,◇,◆,□,■,△,▲,※,→,←,↑,↓,〓,〡,〢,〣,〤,〥,〦,〧,〨,〩,㊣,㎎,㎏,㎜,㎝,㎞,㎡,㏄,㏎,㏑,㏒,㏕,︰,¬,¦,℡,ˊ,ˋ,˙,–,―,‥,‵,℅,℉,↖,↗,↘,↙,∕,∟,∣,≒,≦,≧,⊿,═,║,╒,╓,╔,╕,╖,╗,╘,╙,╚,╛,╜,╝,╞,╟,╠,╡,╢,╣,╤,╥,╦,╧,╨,╩,╪,╫,╬,╭,╮,╯,╰,╱,╲,╳,▁,▂,▃,▄,▅,▆,▇,�,█,▉,▊,▋,▌,▍,▎,▏,▓,▔,▕,▼,▽,◢,◣,◤,◥,☉,⊕,〒,〝,〞")}, { name:"lmsz", title:lang.lmsz, content:toArray("ⅰ,ⅱ,ⅲ,ⅳ,ⅴ,ⅵ,ⅶ,ⅷ,ⅸ,ⅹ,Ⅰ,Ⅱ,Ⅲ,Ⅳ,Ⅴ,Ⅵ,Ⅶ,Ⅷ,Ⅸ,Ⅹ,Ⅺ,Ⅻ")}, { name:"szfh", title:lang.szfh, content:toArray("⒈,⒉,⒊,⒋,⒌,⒍,⒎,⒏,⒐,⒑,⒒,⒓,⒔,⒕,⒖,⒗,⒘,⒙,⒚,⒛,⑴,⑵,⑶,⑷,⑸,⑹,⑺,⑻,⑼,⑽,⑾,⑿,⒀,⒁,⒂,⒃,⒄,⒅,⒆,⒇,①,②,③,④,⑤,⑥,⑦,⑧,⑨,⑩,㈠,㈡,㈢,㈣,㈤,㈥,㈦,㈧,㈨,㈩")}, @@ -16,42 +19,73 @@ var charsContent = [ { name:"yyyb", title:lang.yyyb, content:toArray("i:,i,e,æ,ʌ,ə:,ə,u:,u,ɔ:,ɔ,a:,ei,ai,ɔi,əu,au,iə,εə,uə,p,t,k,b,d,g,f,s,ʃ,θ,h,v,z,ʒ,ð,tʃ,tr,ts,dʒ,dr,dz,m,n,ŋ,l,r,w,j,")}, { name:"zyzf", title:lang.zyzf, content:toArray("ㄅ,ㄆ,ㄇ,ㄈ,ㄉ,ㄊ,ㄋ,ㄌ,ㄍ,ㄎ,ㄏ,ㄐ,ㄑ,ㄒ,ㄓ,ㄔ,ㄕ,ㄖ,ㄗ,ㄘ,ㄙ,ㄚ,ㄛ,ㄜ,ㄝ,ㄞ,ㄟ,ㄠ,ㄡ,ㄢ,ㄣ,ㄤ,ㄥ,ㄦ,ㄧ,ㄨ")} ]; + +// 定义一个立即执行函数,传入charsContent作为参数,用于创建选项卡相关的DOM结构以及绑定交互逻辑 (function createTab(content) { + // 循环遍历传入的content数组(也就是charsContent) for (var i = 0, ci; ci = content[i++];) { + // 创建一个元素,后续用于作为选项卡的标题之类的显示元素 var span = document.createElement("span"); + // 给创建的元素设置一个自定义属性tabSrc,值为当前对象的name属性(用于后续识别和关联) span.setAttribute("tabSrc", ci.name); + // 将当前对象的title属性值设置为元素的innerHTML,也就是显示的文本内容 span.innerHTML = ci.title; + // 如果是第一个选项卡(索引为1,因为索引从0开始,这里实际是第二个元素,但符合通常第一个选项卡默认选中的逻辑),给它添加名为"focus"的类名,用于样式上突出显示(比如改变背景色等) if (i == 1)span.className = "focus"; + // 给元素绑定点击事件处理函数 domUtils.on(span, "click", function () { + // 获取id为tabHeads的元素的所有子元素(可能是所有选项卡标题元素) var tmps = $G("tabHeads").children; + // 循环遍历这些子元素,将它们的类名都清空,用于取消之前的选中状态样式 for (var k = 0, sk; sk = tmps[k++];) { sk.className = ""; } + // 获取id为tabBodys的元素的所有子元素(可能是各个选项卡对应的内容区域元素) tmps = $G("tabBodys").children; + // 循环遍历这些子元素,将它们的display样式设置为"none",也就是隐藏起来 for (var k = 0, sk; sk = tmps[k++];) { sk.style.display = "none"; } + // 将当前点击的元素的类名设置为"focus",表示选中状态 this.className = "focus"; + // 根据当前点击元素的tabSrc属性值,获取对应的id的元素,并将其display样式设置为空字符串(一般就是显示出来,恢复默认显示状态) $G(this.getAttribute("tabSrc")).style.display = ""; }); + // 将创建并设置好的元素添加到id为tabHeads的元素中,作为其子元素 $G("tabHeads").appendChild(span); + // 在添加的元素后面插入一个换行的文本节点,用于排版美化之类的(可能影响页面布局呈现效果) domUtils.insertAfter(span, document.createTextNode("\n")); + + // 创建一个
元素,用于作为选项卡的内容区域容器 var div = document.createElement("div"); + // 设置该
元素的id为当前对象的name属性值,方便后续通过id查找和操作 div.id = ci.name; - div.style.display = (i == 1) ? "" : "none"; + // 如果是第一个选项卡(索引为1),将其display样式设置为空字符串(显示出来),否则设置为"none"(隐藏起来) + div.style.display = (i == 1)? "" : "none"; + // 获取当前对象的content属性值(是一个数组,包含了具体的字符内容) var cons = ci.content; + // 循环遍历这个content数组 for (var j = 0, con; con = cons[j++];) { + // 创建一个元素,用于显示单个字符 var charSpan = document.createElement("span"); + // 将当前字符内容设置为元素的innerHTML,也就是显示出来 charSpan.innerHTML = con; + // 给这个用于显示字符的元素绑定点击事件处理函数 domUtils.on(charSpan, "click", function () { + // 调用editor对象的execCommand方法,执行"insertHTML"命令,将当前点击的元素的innerHTML(也就是字符内容)插入到编辑器中(这里的editor应该是外部定义好的编辑器相关对象) editor.execCommand("insertHTML", this.innerHTML); + // 调用dialog对象的close方法,关闭对话框(这里的dialog应该也是外部定义好的相关对象,用于展示这个字符选择的界面等) dialog.close(); }); + // 将创建并设置好的用于显示字符的元素添加到对应的选项卡内容区域的
元素中 div.appendChild(charSpan); } + // 将整个选项卡内容区域的
元素添加到id为tabBodys的元素中,作为其子元素 $G("tabBodys").appendChild(div); } })(charsContent); + +// 定义一个函数toArray,用于将传入的字符串按照逗号进行分割,返回分割后的数组 function toArray(str) { return str.split(","); -} +} \ No newline at end of file diff --git a/public2/ueditor/dialogs/table/edittable.css b/public2/ueditor/dialogs/table/edittable.css index c6f9396..72d276b 100644 --- a/public2/ueditor/dialogs/table/edittable.css +++ b/public2/ueditor/dialogs/table/edittable.css @@ -1,84 +1,137 @@ +/* 对body元素设置样式 */ body{ + /* 超出body元素范围的内容隐藏起来,避免出现滚动条等情况,用于控制页面整体的显示范围 */ overflow: hidden; + /* 设置body元素的宽度为540px,限定整个页面主体的宽度 */ width: 540px; } + +/* 定义名为wrapper的类选择器样式,通常用于包裹页面中的一部分内容区域 */ .wrapper { + /* 设置上下外边距,上外边距为10px,下外边距自动(会根据父元素宽度等情况自动调整,实现水平居中效果),左外边距为0,让其在水平方向上相对父元素居中显示 */ margin: 10px auto 0; + /* 设置字体大小为12px,统一该区域内文字的字号 */ font-size: 12px; + /* 超出该元素范围的内容隐藏起来,避免内部元素溢出显示异常 */ overflow: hidden; + /* 设置宽度为520px,确定这个包裹区域的宽度 */ width: 520px; + /* 设置高度为315px,确定这个包裹区域的高度 */ height: 315px; } +/* 定义名为clear的类选择器样式,一般用于清除浮动带来的影响,确保后续元素的布局正常 */ .clear { + /* 清除左右两侧的浮动元素,使该元素不会受到前面浮动元素的影响,能按正常流布局显示 */ clear: both; } -.wrapper .left { +/* 对同时应用了wrapper类和left类的元素设置样式,通常用于布局中靠左边的部分内容 */ +.wrapper.left { + /* 让元素向左浮动,使其能在同一行内从左到右依次排列(前提是有足够宽度),常用于多栏布局 */ float: left; - margin-left: 10px;; + /* 设置左外边距为10px,拉开与左边元素或容器边界的距离 */ + margin-left: 10px; } -.wrapper .right { +/* 对同时应用了wrapper类和right类的元素设置样式,通常用于布局中靠右边的部分内容 */ +.wrapper.right { + /* 让元素向右浮动,使其能在同一行内从右到左依次排列(前提是有足够宽度),常用于多栏布局 */ float: right; + /* 设置左边框为2px的点状边框,颜色为#EDEDED,用于视觉上区分左右两部分内容区域 */ border-left: 2px dotted #EDEDED; + /* 设置左内边距为15px,增加内部内容与左边框的距离,使显示更美观 */ padding-left: 15px; } +/* 定义名为section的类选择器样式,可能用于页面中不同的功能或内容板块 */ .section { + /* 设置下外边距为15px,拉开与下方相邻元素的距离,增加板块之间的间隔 */ margin-bottom: 15px; + /* 设置宽度为240px,限定每个板块的宽度 */ width: 240px; + /* 超出该元素范围的内容隐藏起来,避免内部元素溢出显示异常 */ overflow: hidden; } +/* 对类名为section下的h3元素设置样式,一般用于板块内的标题样式设置 */ .section h3 { + /* 设置字体加粗,突出标题显示效果 */ font-weight: bold; + /* 设置上下内边距为5px,增加标题内容的上下空白区域,使其更美观 */ padding: 5px 0; + /* 设置下外边距为10px,拉开与下方相邻元素(比如标题下方的列表等内容)的距离 */ margin-bottom: 10px; + /* 设置下边框为1px的实线边框,颜色为#EDEDED,用于视觉上对标题区域进行区分 */ border-bottom: 1px solid #EDEDED; + /* 设置字体大小为12px,统一板块标题的字号 */ font-size: 12px; } +/* 对类名为section下的ul元素设置样式,通常用于设置板块内的无序列表样式 */ .section ul { + /* 去除列表默认的项目符号样式,可能会根据后续需求自定义列表项的显示样式 */ list-style: none; + /* 超出该元素范围的内容隐藏起来,避免内部元素溢出显示异常 */ overflow: hidden; + /* 清除左右两侧的浮动元素,确保列表在布局中正常显示,不受前面浮动元素影响 */ clear: both; - } +/* 对类名为section下的li元素设置样式,用于设置板块内列表项的样式 */ .section li { + /* 让列表项向左浮动,使其能在同一行内从左到右依次排列(前提是有足够宽度),实现多列布局效果等 */ float: left; - width: 120px;; + /* 设置列表项的宽度为120px,控制每个列表项的水平占宽情况 */ + width: 120px; } -.section .tone { - width: 80px;; +/* 对类名为section下的tone类元素设置样式,可能是特定用途的元素样式,比如表示某种色调之类的元素 */ +.section.tone { + /* 设置宽度为80px,限定该类元素的宽度 */ + width: 80px; } -.section .preview { +/* 对类名为section下的preview类元素设置样式,可能用于展示预览相关内容的元素 */ +.section.preview { + /* 设置宽度为220px,限定该类元素的宽度 */ width: 220px; } -.section .preview table { +/* 对类名为section下的preview类中的table元素设置样式,用于设置表格的整体样式 */ +.section.preview table { + /* 设置表格内容水平居中对齐 */ text-align: center; + /* 设置表格内容垂直居中对齐,使表格内文字等内容在单元格中垂直方向上处于中间位置 */ vertical-align: middle; + /* 设置表格内文字颜色为#666,统一表格内容的文字颜色 */ color: #666; } -.section .preview caption { +/* 对类名为section下的preview类中的caption元素设置样式,一般用于表格标题的样式设置 */ +.section.preview caption { + /* 设置字体加粗,突出表格标题显示效果 */ font-weight: bold; } -.section .preview td { +/* 对类名为section下的preview类中的td元素设置样式,用于设置表格数据单元格的样式 */ +.section.preview td { + /* 设置边框宽度为1px,四条边的边框样式都为实线,后续可通过border-color等属性设置边框颜色等 */ border-width: 1px; border-style: solid; + /* 设置单元格的高度为22px,统一表格数据单元格的高度 */ height: 22px; } -.section .preview th { +/* 对类名为section下的preview类中的th元素设置样式,用于设置表格表头单元格的样式 */ +.section.preview th { + /* 设置边框样式为实线,通过border-color属性可以设置不同边的边框颜色 */ border-style: solid; + /* 设置边框颜色,上边框宽度为2px,左右下边框宽度为1px,且颜色都为#DDD */ border-color: #DDD; border-width: 2px 1px 1px 1px; + /* 设置单元格的高度为22px,统一表格表头单元格的高度 */ height: 22px; + /* 设置表头单元格的背景颜色为#F7F7F7,用于视觉上区分表头和数据单元格 */ background-color: #F7F7F7; } \ No newline at end of file diff --git a/public2/ueditor/dialogs/table/edittable.html b/public2/ueditor/dialogs/table/edittable.html index 3c412fb..c860337 100644 --- a/public2/ueditor/dialogs/table/edittable.html +++ b/public2/ueditor/dialogs/table/edittable.html @@ -1,64 +1,100 @@ + + + + -
-
-
-

-
    -
  • - -
  • -
  • - -
  • -
-
    -
  • - -
  • -
  • - -
  • -
-
-
-
-

-
    -
  • - -
  • -
  • - -
  • -
-
-
-
-

-
    -
  • - - -
  • -
-
+ +
+ +
+ +
+ +

+
    + +
  • + + +
  • +
  • + +
  • +
+
    +
  • + +
  • +
  • + +
  • +
+ +
+
+
+

+
    +
  • + +
  • +
  • + +
  • +
+
+
+
+

+
    +
  • + + + + +
  • +
+
+
-
-
-
-

-
+
+
+

+ +
+
-
- + + \ No newline at end of file diff --git a/public2/ueditor/dialogs/table/edittable.js b/public2/ueditor/dialogs/table/edittable.js index 11dbee7..7dbfb91 100644 --- a/public2/ueditor/dialogs/table/edittable.js +++ b/public2/ueditor/dialogs/table/edittable.js @@ -4,8 +4,11 @@ * Date: 12-12-19 * Time: 下午4:55 * To change this template use File | Settings | File Templates. + * 上面这部分是代码的文件头注释,包含了创建文件所使用的编辑器(JetBrains PhpStorm)、作者(xuheng)、创建日期以及关于修改模板相关的提示信息等,主要用于代码的溯源和基本信息记录 */ +// 定义一个立即执行函数,用于创建一个独立的作用域,避免变量污染全局环境 (function () { + // 获取页面中id为J_title的元素,通常这些元素可能是与表格编辑相关的表单元素(如复选框等),以下类似的获取操作同理 var title = $G("J_title"), titleCol = $G("J_titleCol"), caption = $G("J_caption"), @@ -16,74 +19,103 @@ me, preview = $G("J_preview"); + // 定义一个名为editTable的构造函数,用于创建编辑表格相关功能的对象实例 var editTable = function () { me = this; + // 调用对象自身的init方法进行初始化操作 me.init(); }; + // 将editTable的原型对象进行扩展,添加一系列方法,用于实现具体的表格编辑相关功能 editTable.prototype = { + // init方法,用于初始化各种状态、绑定事件等操作 init:function () { + // 创建一个UE.ui.ColorPicker实例,用于选择颜色,传入编辑器对象(这里的editor应该是外部定义好的编辑器相关对象) var colorPiker = new UE.ui.ColorPicker({ editor:editor }), + // 创建一个UE.ui.Popup实例,用于弹出颜色选择器相关的界面,传入编辑器对象,并将颜色选择器作为其内容 colorPop = new UE.ui.Popup({ editor:editor, content:colorPiker }); + // 根据编辑器中"inserttitle"命令的状态(-1可能表示未启用之类的情况)来设置title复选框的选中状态 title.checked = editor.queryCommandState("inserttitle") == -1; titleCol.checked = editor.queryCommandState("inserttitlecol") == -1; caption.checked = editor.queryCommandState("insertcaption") == -1; sorttable.checked = editor.queryCommandState("enablesort") == 1; + // 获取编辑器中"enablesort"命令的状态 var enablesortState = editor.queryCommandState("enablesort"), disablesortState = editor.queryCommandState("disablesort"); - sorttable.checked = !!(enablesortState < 0 && disablesortState >=0); - sorttable.disabled = !!(enablesortState < 0 && disablesortState < 0); - sorttable.title = enablesortState < 0 && disablesortState < 0 ? lang.errorMsg:''; + // 根据"enablesort"和"disablesort"命令的状态来设置sorttable复选框的选中和禁用状态,并设置提示标题(如果两个状态都小于0可能表示不可用情况等) + sorttable.checked =!!(enablesortState < 0 && disablesortState >=0); + sorttable.disabled =!!(enablesortState < 0 && disablesortState < 0); + sorttable.title = enablesortState < 0 && disablesortState < 0? lang.errorMsg:''; + // 调用对象自身的方法创建表格,传入相关复选框的选中状态作为参数 me.createTable(title.checked, titleCol.checked, caption.checked); + // 调用对象自身的方法设置表格自动尺寸相关逻辑 me.setAutoSize(); + // 调用对象自身的方法设置表格颜色,传入获取到的颜色值作为参数 me.setColor(me.getColor()); + // 给title元素绑定点击事件处理函数,点击时调用对象自身的titleHanler方法 domUtils.on(title, "click", me.titleHanler); + // 给titleCol元素绑定点击事件处理函数,点击时调用对象自身的titleColHanler方法 domUtils.on(titleCol, "click", me.titleColHanler); + // 给caption元素绑定点击事件处理函数,点击时调用对象自身的captionHanler方法 domUtils.on(caption, "click", me.captionHanler); + // 给sorttable元素绑定点击事件处理函数,点击时调用对象自身的sorttableHanler方法 domUtils.on(sorttable, "click", me.sorttableHanler); + // 给autoSizeContent元素绑定点击事件处理函数,点击时调用对象自身的autoSizeContentHanler方法 domUtils.on(autoSizeContent, "click", me.autoSizeContentHanler); + // 给autoSizePage元素绑定点击事件处理函数,点击时调用对象自身的autoSizePageHanler方法 domUtils.on(autoSizePage, "click", me.autoSizePageHanler); + // 给tone元素绑定点击事件处理函数,点击时显示颜色选择器弹出框,并定位到tone元素位置 domUtils.on(tone, "click", function () { colorPop.showAnchor(tone); }); + // 给document文档对象绑定鼠标按下事件处理函数,点击时隐藏颜色选择器弹出框 domUtils.on(document, 'mousedown', function () { colorPop.hide(); }); + // 给颜色选择器添加"pickcolor"事件的监听器,当选择颜色时调用对象自身的setColor方法设置颜色,并隐藏弹出框 colorPiker.addListener("pickcolor", function () { me.setColor(arguments[1]); colorPop.hide(); }); + // 给颜色选择器添加"picknocolor"事件的监听器,当不选择颜色(比如取消选择)时调用对象自身的setColor方法设置为空颜色,并隐藏弹出框 colorPiker.addListener("picknocolor", function () { me.setColor(""); colorPop.hide(); }); }, + // 创建表格的方法,根据传入的是否有标题、标题列、标题说明等参数来构建表格的HTML结构 createTable:function (hasTitle, hasTitleCol, hasCaption) { var arr = [], sortSpan = '^'; + // 将表格开始标签添加到数组中,后续通过join方法拼接成完整的HTML字符串 arr.push(""); + // 如果传入的hasCaption为true,表示有标题说明,则添加标题说明的HTML结构到数组中 if (hasCaption) { arr.push("") } + // 如果传入的hasTitle为true,表示有标题行,则添加标题行的HTML结构到数组中 if (hasTitle) { arr.push(""); + // 如果同时有标题列(hasTitleCol为true),则添加标题列的表头单元格HTML结构到数组中 if(hasTitleCol) { arr.push(""); } + // 循环添加5个普通表头单元格的HTML结构到数组中 for (var j = 0; j < 5; j++) { arr.push(""); } arr.push(""); } + // 循环添加6行表格数据行的HTML结构到数组中 for (var i = 0; i < 6; i++) { arr.push(""); if(hasTitleCol) { arr.push("") } @@ -92,68 +124,94 @@ } arr.push(""); } + // 将表格结束标签添加到数组中 arr.push("
" + lang.captionName + "
" + lang.titleName + "" + lang.titleName + "
" + lang.titleName + "
"); + // 将拼接好的HTML字符串设置为preview元素的innerHTML,用于在页面中显示表格示例 preview.innerHTML = arr.join(""); + // 调用对象自身的updateSortSpan方法更新排序相关的显示内容(比如排序箭头等) this.updateSortSpan(); }, + // 处理title复选框点击事件的方法 titleHanler:function () { var example = $G("J_example"), frg=document.createDocumentFragment(), + // 获取表格中第一个td单元格的边框颜色,用于后续设置颜色等操作 color = domUtils.getComputedStyle(domUtils.getElementsByTagName(example, "td")[0], "border-color"), colCount = example.rows[0].children.length; + // 如果title复选框被选中 if (title.checked) { + // 在表格的第一行插入新行(用于添加标题行) example.insertRow(0); + // 循环根据表头列数量创建表头单元格元素,并添加到文档片段中 for (var i = 0, node; i < colCount; i++) { node = document.createElement("th"); node.innerHTML = lang.titleName; frg.appendChild(node); } + // 将包含表头单元格的文档片段添加到新插入的第一行中 example.rows[0].appendChild(frg); } else { + // 如果title复选框取消选中,移除表格的第一行(也就是移除标题行) domUtils.remove(example.rows[0]); } + // 调用对象自身的setColor方法设置表格颜色,传入获取到的颜色值 me.setColor(color); + // 调用对象自身的updateSortSpan方法更新排序相关的显示内容 me.updateSortSpan(); }, + // 处理titleCol复选框点击事件的方法 titleColHanler:function () { var example = $G("J_example"), color = domUtils.getComputedStyle(domUtils.getElementsByTagName(example, "td")[0], "border-color"), colArr = example.rows, colCount = colArr.length; + // 如果titleCol复选框被选中 if (titleCol.checked) { + // 循环遍历每一行,在每行的第一个位置插入表头单元格元素 for (var i = 0, node; i < colCount; i++) { node = document.createElement("th"); node.innerHTML = lang.titleName; colArr[i].insertBefore(node, colArr[i].children[0]); } } else { + // 如果titleCol复选框取消选中,循环移除每行的第一个元素(也就是移除之前添加的表头单元格) for (var i = 0; i < colCount; i++) { domUtils.remove(colArr[i].children[0]); } } + // 调用对象自身的setColor方法设置表格颜色,传入获取到的颜色值 me.setColor(color); + // 调用对象自身的updateSortSpan方法更新排序相关的显示内容 me.updateSortSpan(); }, + // 处理caption复选框点击事件的方法 captionHanler:function () { var example = $G("J_example"); + // 如果caption复选框被选中 if (caption.checked) { + // 创建一个caption元素(标题说明元素),设置其innerHTML为相应的文本内容 var row = document.createElement('caption'); row.innerHTML = lang.captionName; + // 将创建的caption元素插入到表格的第一个子元素位置(也就是作为标题说明) example.insertBefore(row, example.firstChild); } else { + // 如果caption复选框取消选中,移除表格中的标题说明元素(通过获取第一个caption元素来移除) domUtils.remove(domUtils.getElementsByTagName(example, 'caption')[0]); } }, + // 处理sorttable复选框点击事件的方法,主要是更新排序相关的显示内容 sorttableHanler:function(){ me.updateSortSpan(); }, + // 处理autoSizeContent单选框点击事件的方法,移除表格的宽度属性,使表格根据内容自适应宽度 autoSizeContentHanler:function () { var example = $G("J_example"); example.removeAttribute("width"); }, + // 处理autoSizePage单选框点击事件的方法,设置表格宽度为100%,并移除表格内每个td单元格的宽度属性,使表格根据页面宽度自适应 autoSizePageHanler:function () { var example = $G("J_example"); var tds = example.getElementsByTagName(example, "td"); @@ -162,6 +220,7 @@ }); example.setAttribute('width', '100%'); }, + // 更新排序相关显示内容的方法,比如添加或移除排序箭头等 updateSortSpan: function(){ var example = $G("J_example"), row = example.rows[0]; @@ -178,6 +237,7 @@ }); } }, + // 获取表格颜色的方法,通过获取当前选择位置所在单元格的边框颜色来确定,如果没有获取到则返回默认颜色#DDDDDD getColor:function () { var start = editor.selection.getStart(), color, cell = domUtils.findParentByTagName(start, ["td", "th", "caption"], true); @@ -185,6 +245,7 @@ if (!color) color = "#DDDDDD"; return color; }, + // 设置表格颜色的方法,设置表格中所有td、th、caption元素的边框颜色,并更新tone元素(可能是显示颜色的输入框之类的)的值 setColor:function (color) { var example = $G("J_example"), arr = domUtils.getElementsByTagName(example, "td").concat( @@ -198,6 +259,7 @@ }); }, + // 设置表格自动尺寸的方法,默认选中autoSizePage单选框,并调用其对应的处理方法来设置表格尺寸 setAutoSize:function () { var me = this; autoSizePage.checked = true; @@ -205,8 +267,10 @@ } }; + // 创建一个editTable的实例,启动整个表格编辑相关的功能逻辑 new editTable; + // 给dialog对象(可能是对话框相关对象)的onok属性设置一个函数,当点击对话框的确定按钮时执行以下逻辑 dialog.onok = function () { editor.__hasEnterExecCommand = true; @@ -216,6 +280,7 @@ caption:"insertcaption deletecaption", sorttable:"enablesort disablesort" }; + // 触发编辑器的'saveScene'事件 editor.fireEvent('saveScene'); for(var i in checks){ var cmds = checks[i].split(" "), @@ -228,8 +293,8 @@ } editor.execCommand("edittable", tone.value); - autoSizeContent.checked ?editor.execCommand('adaptbytext') : ""; - autoSizePage.checked ? editor.execCommand("adaptbywindow") : ""; + autoSizeContent.checked?editor.execCommand('adaptbytext') : ""; + autoSizePage.checked? editor.execCommand("adaptbywindow") : ""; editor.fireEvent('saveScene'); editor.__hasEnterExecCommand = false; diff --git a/public2/ueditor/dialogs/table/edittd.html b/public2/ueditor/dialogs/table/edittd.html index 49a52f7..e340df8 100644 --- a/public2/ueditor/dialogs/table/edittd.html +++ b/public2/ueditor/dialogs/table/edittd.html @@ -1,61 +1,87 @@ + + + -
- - -
- + \ No newline at end of file diff --git a/public2/ueditor/dialogs/table/edittip.html b/public2/ueditor/dialogs/table/edittip.html index 954f7bb..bdbe896 100644 --- a/public2/ueditor/dialogs/table/edittip.html +++ b/public2/ueditor/dialogs/table/edittip.html @@ -1,33 +1,57 @@ + + 表格删除提示 + -
-
- + +
+ +
+ + +
+
+ +
-
- -
-
- + \ No newline at end of file diff --git a/public2/ueditor/dialogs/template/config.js b/public2/ueditor/dialogs/template/config.js index 417b8f7..76ab39b 100644 --- a/public2/ueditor/dialogs/template/config.js +++ b/public2/ueditor/dialogs/template/config.js @@ -5,37 +5,50 @@ * Time: 下午2:00 * To change this template use File | Settings | File Templates. */ + +// 定义一个名为 `templates` 的数组,数组中的每个元素都是一个对象,用于存储不同文档模板的相关信息,可能用于在文本编辑器等应用中提供多种预设的文档模板供用户选择使用。 var templates = [ { - "pre":"pre0.png", - 'title':lang.blank, - 'preHtml':'

 欢迎使用UEditor!

', - "html":'

欢迎使用UEditor!

' + // `pre` 属性用于指定该模板对应的预览图片文件名(这里仅包含文件名,推测图片文件的路径在其他地方有统一配置或者约定),值为 "pre0.png",可能用于在模板选择界面展示该模板的缩略图等可视化表示。 + "pre": "pre0.png", + // `title` 属性用于存储模板的标题,其值来自 `lang` 对象中的 `blank` 属性(推测 `lang` 是一个用于存储多语言文本的对象,根据不同语言环境获取对应的文本内容,这里 `blank` 对应的文本可能表示空白模板之类的含义),用于在模板列表等地方向用户展示该模板的名称。 + 'title': lang.blank, + // `preHtml` 属性存储了该模板的部分 HTML 代码片段,这部分代码可能是用于在模板预览或者初始加载时展示的简略内容,例如这里是一个简单的包含欢迎语的 `

` 标签内容,用于给用户一个该模板大致样子的预览效果。 + 'preHtml': '

 欢迎使用UEditor!

', + // `html` 属性同样存储的是 HTML 代码,但可能是该模板完整或者更详细的用于实际编辑使用的代码内容,这里也是一个包含欢迎语的 `

` 标签内容,不过与 `preHtml` 中的内容可能在后续编辑过程中有不同的用途或者可编辑性等方面的差异。 + "html": '

欢迎使用UEditor!

' }, { - "pre":"pre1.png", - 'title':lang.blog, - 'preHtml':'

深入理解Range

UEditor二次开发

什么是Range

对于“插入”选项卡上的库,在设计时都充分考虑了其中的项与文档整体外观的协调性。


Range能干什么

在“开始”选项卡上,通过从快速样式库中为所选文本选择一种外观,您可以方便地更改文档中所选文本的格式。

', - "html":'

[键入文档标题]

[键入文档副标题]

[标题 1]

对于“插入”选项卡上的库,在设计时都充分考虑了其中的项与文档整体外观的协调性。 您可以使用这些库来插入表格、页眉、页脚、列表、封面以及其他文档构建基块。 您创建的图片、图表或关系图也将与当前的文档外观协调一致。

[标题 2]

在“开始”选项卡上,通过从快速样式库中为所选文本选择一种外观,您可以方便地更改文档中所选文本的格式。 您还可以使用“开始”选项卡上的其他控件来直接设置文本格式。大多数控件都允许您选择是使用当前主题外观,还是使用某种直接指定的格式。

[标题 3]

对于“插入”选项卡上的库,在设计时都充分考虑了其中的项与文档整体外观的协调性。 您可以使用这些库来插入表格、页眉、页脚、列表、封面以及其他文档构建基块。 您创建的图片、图表或关系图也将与当前的文档外观协调一致。


' + "pre": "pre1.png", + 'title': lang.blog, + // 该模板的 `preHtml` 属性存储了一段较为复杂的 HTML 代码,用于展示类似博客文章格式的预览内容,包含标题(`

` 标签,设置了一些样式属性,如边框底部样式、颜色、宽度以及文本对齐方式等)、副标题(`

` 标签内的 `` 标签)以及不同层级的标题(`

` 标签)和对应的段落文本(`

` 标签,设置了首行缩进等样式),整体呈现出一篇博客文章的大致结构和样式示例。 + 'preHtml': '

深入理解Range

UEditor二次开发

什么是Range

对于“插入”选项卡上的库,在设计时都充分考虑了其中的项与文档整体外观的协调性。


Range能干什么

在“开始”选项卡上,通过从快速样式库中为所选文本选择一种外观,您可以方便地更改文档中所选文本的格式。

', + // `html` 属性中的 HTML 代码同样是类似博客文章格式的内容,但其中一些文本部分使用 `[键入文档标题]`、`[键入文档副标题]` 等占位符替换了实际内容,表明这是一个更通用的博客文章模板,用户可以根据自己的需求在相应位置输入具体的标题、副标题以及各部分内容,用于实际创建一篇完整的博客文章。 + "html": '

[键入文档标题]

[键入文档副标题]

[标题 1]

对于“插入”选项卡上的库,在设计时都充分考虑了其中的项与文档整体外观的协调性。 您可以使用这些库来插入表格、页眉、页脚、列表、封面以及其他文档构建基块。 您创建的图片、图表或关系图也将与当前的文档外观协调一致。

[标题 2]

在“开始”选项卡上,通过从快速样式库中为所选文本选择一种外观,您可以方便地更改文档中所选文本的格式。 您还可以使用“开始”选项卡上的其他控件来直接设置文本格式。大多数控件都允许您选择是使用当前主题外观,还是使用某种直接指定的格式。

[标题 3]

对于“插入”选项卡上的库,在设计时都充分考虑了其中的项与文档整体外观的协调性。 您可以使用这些库来插入表格、页眉、页脚、列表、封面以及其他文档构建基块。 您创建的图片、图表或关系图也将与当前的文档外观协调一致。


' }, { - "pre":"pre2.png", - 'title':lang.resume, - 'preHtml':'

WEB前端开发简历


联系电话:[键入您的电话]

电子邮件:[键入您的电子邮件地址]

家庭住址:[键入您的地址]

目标职位

WEB前端研发工程师

学历

  1. [起止时间] [学校名称] [所学专业] [所获学位]

工作经验


', - "html":'

[此处键入简历标题]


【此处插入照片】


联系电话:[键入您的电话]


电子邮件:[键入您的电子邮件地址]


家庭住址:[键入您的地址]


目标职位

[此处键入您的期望职位]

学历

  1. [键入起止时间] [键入学校名称] [键入所学专业] [键入所获学位]

  2. [键入起止时间] [键入学校名称] [键入所学专业] [键入所获学位]

工作经验

  1. [键入起止时间] [键入公司名称] [键入职位名称]

    1. [键入负责项目] [键入项目简介]

    2. [键入负责项目] [键入项目简介]

  2. [键入起止时间] [键入公司名称] [键入职位名称]

    1. [键入负责项目] [键入项目简介]

掌握技能

 [这里可以键入您所掌握的技能]

' + "pre": "pre2.png", + 'title': lang.resume, + // 此模板的 `preHtml` 属性中的 HTML 代码呈现出简历格式的预览内容,包含简历标题(`

` 标签,设置了样式属性)、一个简单的表格(用于展示联系方式等信息,设置了边框样式、宽度等属性)以及不同层级的标题(如目标职位、学历、工作经验等对应的 `

` 标签)和相应的文本内容,初步展示了一份简历的大致结构和样式示例。 + 'preHtml': '

WEB前端开发简历


联系电话:[键入您的电话]

电子邮件:[键入您的电子邮件地址]

家庭住址:[键入您的地址]

目标职位

WEB前端研发工程师

学历

  1. [起止时间] [学校名称] [所学专业] [所获学位]

工作经验


', + // `html` 属性中的 HTML 代码则是更完整通用的简历模板内容,在各部分相应位置使用占位符(如 `[此处键入简历标题]`、`[键入您的电话]`、`[键入起止时间]` 等)替代了具体内容,方便用户根据自己实际情况填写各项信息,构建一份完整的简历文档。 + "html": '

[此处键入简历标题]


【此处插入照片】


联系电话:[键入您的电话]


电子邮件:[键入您的电子邮件地址]


家庭住址:[键入您的地址]


目标职位

[此处键入您的期望职位]

学历

  1. [键入起止时间] [键入学校名称] [键入所学专业] [键入所获学位]

  2. [键入起止时间] [键入学校名称] [键入所学专业] [键入所获学位]

工作经验

  1. [键入起止时间] [键入公司名称] [键入职位名称]

    1. [键入负责项目] [键入项目简介]

    2. [键入负责项目] [键入项目简介]

  2. [键入起止时间] [键入公司名称] [键入职位名称]

    1. [键入负责项目] [键入项目简介]

掌握技能

 [这里可以键入您所掌握的技能]

' }, { - "pre":"pre3.png", - 'title':lang.richText, - 'preHtml':'

[此处键入文章标题]

图文混排方法

图片居左,文字围绕图片排版

方法:在文字前面插入图片,设置居左对齐,然后即可在右边输入多行文


还有没有什么其他的环绕方式呢?这里是居右环绕


欢迎大家多多尝试,为UEditor提供更多高质量模板!

', - "html":'


[此处键入文章标题]

图文混排方法

1. 图片居左,文字围绕图片排版

方法:在文字前面插入图片,设置居左对齐,然后即可在右边输入多行文本


2. 图片居右,文字围绕图片排版

方法:在文字前面插入图片,设置居右对齐,然后即可在左边输入多行文本


3. 图片居中环绕排版

方法:亲,这个真心没有办法。。。



还有没有什么其他的环绕方式呢?这里是居右环绕


欢迎大家多多尝试,为UEditor提供更多高质量模板!


占位


占位


占位


占位


占位



' + "pre": "pre3.png", + 'title': lang.richText, + // `preHtml` 属性中的 HTML 代码展示了一个图文混排样式的富文本内容预览,包含标题(`

` 标签)、图片(`` 标签,设置了图片来源、尺寸、对齐方式等属性,呈现出图片居左和居右的不同排版示例)以及相关的文字描述,展示了一种图文混排的文档结构和样式效果,用于让用户了解该模板可实现的排版风格。 + 'preHtml': '

[此处键入文章标题]

图文混排方法

图片居左,文字围绕图片排版

方法:在文字前面插入图片,设置居左对齐,然后即可在右边输入多行文


还有没有什么其他的环绕方式呢?这里是居右环绕


欢迎大家多多尝试,为UEditor提供更多高质量模板!

', + // `html` 属性中的 HTML 代码则进一步丰富了图文混排的示例内容,增加了更多关于图文混排的描述(如不同环绕方式的介绍、更多的占位文本等),同样是一个用于实际创建富文本内容时可参考和编辑的通用模板,用户可在相应位置修改文本、替换图片等操作来生成符合自己需求的富文本文档。 + "html": '


[此处键入文章标题]

图文混排方法

1. 图片居左,文字围绕图片排版

方法:在文字前面插入图片,设置居左对齐,然后即可在右边输入多行文本


2. 图片居右,文字围绕图片排版

方法:在文字前面插入图片,设置居右对齐,然后即可在左边输入多行文本


3. 图片居中环绕排版

方法:亲,这个真心没有办法。。。



还有没有什么其他的环绕方式呢?这里是居右环绕


欢迎大家多多尝试,为UEditor提供更多高质量模板!


占位


占位


占位


占位


占位



' }, { - "pre":"pre4.png", - 'title':lang.sciPapers, + "pre": "pre4.png", + 'title': lang.sciPapers, + // `preHtml` 属性中的 HTML 代码呈现出类似科学论文格式的内容预览,包含标题(`

` 标签,设置了样式属性)、摘要部分(`

` 标签内包含 `` 标签用于 'preHtml':'

[键入文章标题]

摘要:这里可以输入很长很长很长很长很长很长很长很长很差的摘要

标题 1

这里可以输入很多内容,可以图文混排,可以有列表等。

标题 2

  1. 列表 1

  2. 列表 2

    1. 多级列表 1

    2. 多级列表 2

  3. 列表 3

标题 3

来个文字图文混排的


', 'html':'

[键入文章标题]

摘要:这里可以输入很长很长很长很长很长很长很长很长很差的摘要

标题 1

这里可以输入很多内容,可以图文混排,可以有列表等。

标题 2

来个列表瞅瞅:

  1. 列表 1

  2. 列表 2

    1. 多级列表 1

    2. 多级列表 2

  3. 列表 3

标题 3

来个文字图文混排的

这里可以多行

右边是图片

绝对没有问题的,不信你也可以试试看


' } diff --git a/public2/ueditor/dialogs/template/template.css b/public2/ueditor/dialogs/template/template.css index 6c1608d..63bd0c5 100644 --- a/public2/ueditor/dialogs/template/template.css +++ b/public2/ueditor/dialogs/template/template.css @@ -1,18 +1,142 @@ -.wrap{ padding: 5px;font-size: 14px;} -.left{width:425px;float: left;} -.right{width:160px;border: 1px solid #ccc;float: right;padding: 5px;margin-right: 5px;} -.right .pre{height: 332px;overflow-y: auto;} -.right .preitem{border: white 1px solid;margin: 5px 0;padding: 2px 0;} -.right .preitem:hover{background-color: lemonChiffon;cursor: pointer;border: #ccc 1px solid;} -.right .preitem img{display: block;margin: 0 auto;width:100px;} -.clear{clear: both;} -.top{height:26px;line-height: 26px;padding: 5px;} -.bottom{height:320px;width:100%;margin: 0 auto;} -.transparent{ background: url("images/bg.gif") repeat;} -.bottom table tr td{border:1px dashed #ccc;} -#colorPicker{width: 17px;height: 17px;border: 1px solid #CCC;display: inline-block;border-radius: 3px;box-shadow: 2px 2px 5px #D3D6DA;} -.border_style1{padding:2px;border: 1px solid #ccc;border-radius: 5px;box-shadow:2px 2px 5px #d3d6da;} -p{margin: 5px 0} -table{clear:both;margin-bottom:10px;border-collapse:collapse;word-break:break-all;} -li{clear:both} -ol{padding-left:40px; } \ No newline at end of file +/* 定义一个名为 `.wrap` 的类选择器样式规则,应用该类的元素将会具有以下样式属性。 +设置内边距(padding)为 5 像素,使元素内部的内容与边框之间有一定的间隔; +设置字体大小(font-size)为 14 像素,统一控制该元素内文本的字号大小。 */ +.wrap{ + padding: 5px; + font-size: 14px; +} + +/* 定义一个名为 `.left` 的类选择器样式规则,应用该类的元素通常会是向左浮动(float: left)的布局方式, +并且设置其宽度(width)为 425 像素,常用于将页面划分为左右两部分布局时,定义左边部分元素的宽度和浮动特性,使其能够与其他浮动元素(如右侧部分元素)进行并排排列。 */ +.left{ + width: 425px; + float: left; +} + +/* 定义一个名为 `.right` 的类选择器样式规则,应用该类的元素会向右浮动(float: right),设置宽度为 160 像素, +添加 1 像素宽的实线边框(border: 1px solid #ccc),颜色为浅灰色(#ccc);设置内边距为 5 像素(padding: 5px),使内部内容与边框有间隔; +并设置右边距(margin-right)为 5 像素,用于控制该元素与右侧其他元素的间隔距离,常用于构建页面右侧栏样式等布局场景。 */ +.right{ + width: 160px; + border: 1px solid #ccc; + float: right; + padding: 5px; + margin-right: 5px; +} + +/* 针对类名为 `.right` 内部的类名为 `.pre` 的元素设置样式规则。 +设置其高度(height)为 332 像素,当元素内部内容超出这个高度时,通过 `overflow-y: auto` 属性使垂直方向(y 轴方向)出现滚动条,实现内容的滚动显示,常用于展示内容较多且有固定高度限制的区域,如侧边栏的可滚动内容区域等。 */ +.right.pre{ + height: 332px; + overflow-y: auto; +} + +/* 针对类名为 `.right` 内部的类名为 `.preitem` 的元素设置样式规则。 +设置其边框(border)为 1 像素宽的白色实线(border: white 1px solid),设置上下外边距(margin)为 5 像素、左右外边距为 0,使元素在垂直方向上有间隔,水平方向上紧凑排列; +设置上下内边距(padding)为 2 像素、左右内边距为 0,控制内部内容与边框的间隔距离,整体定义了该元素的基本外观和布局相关的样式属性。 */ +.right.preitem{ + border: white 1px solid; + margin: 5px 0; + padding: 2px 0; +} + +/* 针对类名为 `.right` 内部的类名为 `.preitem` 的元素设置鼠标悬停(`:hover`)时的样式规则,用于实现交互效果。 +当鼠标悬停在该元素上时,改变其背景颜色(background-color)为柠檬绸色(lemonChiffon),使元素有视觉上的突出显示效果; +将鼠标指针样式(cursor)改变为指针形状(cursor: pointer),提示用户该元素可点击交互; +同时改变边框为 1 像素宽的浅灰色(#ccc)实线,替换掉默认的白色边框,增强悬停时的视觉区分度。 */ +.right.preitem:hover{ + background-color: lemonChiffon; + cursor: pointer; + border: #ccc 1px solid; +} + +/* 针对类名为 `.right` 内部的类名为 `.preitem` 的元素内部的 `img` 图片元素设置样式规则。 +设置其显示方式(display)为块级元素(display: block),使其独占一行,方便进行水平居中对齐等布局操作; +设置左右外边距(margin)为自动(auto),实现图片在水平方向上的居中对齐效果; +设置图片的宽度(width)为 100 像素,用于统一控制该类元素内部图片的宽度大小,使其具有一致的外观展示效果。 */ +.right.preitem img{ + display: block; + margin: 0 auto; + width: 100px; +} + +/* 定义一个名为 `.clear` 的类选择器样式规则,通过 `clear: both` 属性清除元素两侧的浮动影响,常用于解决由于浮动元素导致的父元素高度塌陷等布局问题,使后续元素能在正常的文档流中进行布局排列,不受之前浮动元素的干扰。 */ +.clear{ + clear: both; +} + +/* 定义一个名为 `.top` 的类选择器样式规则,设置元素的高度(height)为 26 像素,行高(line-height)也为 26 像素,使文本在垂直方向上能居中对齐; +设置内边距(padding)为 5 像素,用于控制内部内容与边框的间隔距离,常用于页面顶部导航栏、标题栏等具有固定高度和内边距要求的区域样式设置。 */ +.top{ + height: 26px; + line-height: 26px; + padding: 5px; +} + +/* 定义一个名为 `.bottom` 的类选择器样式规则,设置元素的高度(height)为 320 像素,宽度(width)为 100%(即占满父元素的宽度), +设置上下外边距(margin)为 0 且左右外边距为自动(auto),使其在水平方向上能居中对齐,常用于页面底部内容区域等具有固定高度和宽度要求以及居中布局需求的样式设置。 */ +.bottom{ + height: 320px; + width: 100%; + margin: 0 auto; +} + +/* 定义一个名为 `.transparent` 的类选择器样式规则,通过 `background` 属性设置元素的背景为指定的图片(images/bg.gif)并进行重复平铺(repeat), +常用于创建具有特定背景图案且重复铺满整个元素背景区域的效果,可能用于页面的装饰性背景或者特定模块的背景样式设置等场景。 */ +.transparent{ + background: url("images/bg.gif") repeat; +} + +/* 针对类名为 `.bottom` 内部的表格(table)元素内部的 `tr` 行元素内部的 `td` 单元格元素设置样式规则。 +为单元格添加 1 像素宽的虚线边框(border: 1px dashed #ccc),颜色为浅灰色(#ccc),用于区分不同的单元格,增强表格的可视化效果,常用于需要有一定边框样式但又不想使用实线边框显得过于生硬的表格样式设置场景。 */ +.bottom table tr td{ + border: 1px dashed #ccc; +} + +/* 定义一个 `id` 为 `colorPicker` 的元素的样式规则,设置其宽度(width)和高度(height)均为 17 像素,创建一个小的方形元素; +添加 1 像素宽的浅灰色(#CCC)实线边框(border: 1px solid #CCC);设置其显示方式(display)为内联块级元素(display: inline-block),使其既可以像内联元素一样在一行内排列,又能像块级元素一样设置宽度、高度等属性; +添加 3 像素的边框圆角(border-radius: 3px),使其边角变得圆润,增加外观的美观度; +添加阴影效果(box-shadow: 2px 2px 5px #D3D6DA),通过指定水平和垂直方向的偏移量以及模糊半径等参数,营造出元素的立体和层次感,常用于颜色选择器等需要突出显示且有一定交互效果的小元素样式设置场景。 */ +#colorPicker{ + width: 17px; + height: 17px; + border: 1px solid #CCC; + display: inline-block; + border-radius: 3px; + box-shadow: 2px 2px 5px #D3D6DA; +} + +/* 定义一个名为 `.border_style1` 的类选择器样式规则,设置内边距(padding)为 2 像素,添加 1 像素宽的浅灰色(#ccc)实线边框(border: 1px solid #ccc); +设置 5 像素的边框圆角(border-radius: 5px),使元素边角更加圆润;添加阴影效果(box-shadow: 2px 2px 5px #d3d6da),营造出一定的立体和层次感,常用于创建具有特定边框、内边距以及立体效果的按钮、卡片等元素的样式设置场景。 */ +.border_style1{ + padding: 2px; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 2px 2px 5px #d3d6da; +} + +/* 针对页面中的 `p` 段落元素设置样式规则,设置其上下外边距(margin)为 5 像素、左右外边距为 0,使段落之间在垂直方向上有一定的间隔,方便文本内容的阅读和区分不同段落,常用于统一页面中所有段落的基本布局样式设置。 */ +p{ + margin: 5px 0; +} + +/* 针对页面中的表格(table)元素设置样式规则,通过 `clear: both` 属性清除表格元素两侧的浮动影响,确保表格在文档流中的正常布局; +设置下外边距(margin-bottom)为 10 像素,使表格与下方元素有一定的间隔距离; +设置表格的边框合并方式(border-collapse)为合并(collapse),使相邻单元格的边框合并为一条,让表格外观更加简洁整齐; +设置 `word-break: break-all` 属性,当文本内容超出单元格宽度时,允许在单词内任意位置换行,避免出现文本溢出单元格的情况,常用于确保表格内文本能完整显示且布局合理的样式设置场景。 */ +table{ + clear: both; + margin-bottom: 10px; + border-collapse: collapse; + word-break: break-all; +} + +/* 针对页面中的 `li` 列表项元素设置样式规则,通过 `clear: both` 属性清除列表项两侧的浮动影响,确保列表项在文档流中的正常布局排列,常用于有序列表(ol)、无序列表(ul)中的列表项样式设置场景,避免列表项因浮动等原因出现布局混乱的问题。 */ +li{ + clear: both; +} + +/* 针对页面中的有序列表(ol)元素设置样式规则,设置其左内边距(padding-left)为 40 像素,用于控制有序列表的编号与列表项内容之间的间隔距离,使列表项整体有一定的缩进效果,更加美观和易读,常用于统一页面中有序列表的基本样式设置。 */ +ol{ + padding-left: 40px; +} \ No newline at end of file diff --git a/public2/ueditor/dialogs/template/template.html b/public2/ueditor/dialogs/template/template.html index d9903a4..d9ea8be 100644 --- a/public2/ueditor/dialogs/template/template.html +++ b/public2/ueditor/dialogs/template/template.html @@ -2,25 +2,40 @@ - + + + + +
+
+
+ +
+
-
+
+ +
+
+
+ + - + \ No newline at end of file diff --git a/public2/ueditor/dialogs/template/template.js b/public2/ueditor/dialogs/template/template.js index 80a334b..d2a09b4 100644 --- a/public2/ueditor/dialogs/template/template.js +++ b/public2/ueditor/dialogs/template/template.js @@ -5,49 +5,74 @@ * Time: 下午2:09 * To change this template use File | Settings | File Templates. */ + +// 创建一个自执行函数,用于封装相关变量和函数,避免全局变量污染,使得这些代码逻辑相对独立,内部定义的变量和函数不会直接暴露在全局作用域下,除非特意通过 `window` 对象进行挂载。 (function () { + // 获取编辑器对象(`editor`),并赋值给变量 `me`,推测 `editor` 是整个应用中与文本编辑相关的核心对象,包含了各种编辑操作的方法、属性等,后续通过它来执行诸如清除文档、应用模板等命令操作。 var me = editor, - preview = $G( "preview" ), - preitem = $G( "preitem" ), + // 通过 `$G` 函数(可能是自定义的用于获取页面元素的函数,根据传入的 `ID` 来获取对应的 DOM 元素)获取 `ID` 为 "preview" 的页面元素,并赋值给变量 `preview`,从名称推测这个元素可能用于展示模板的预览内容,比如显示模板对应的 HTML 代码呈现出来的样子。 + preview = $G("preview"), + // 同样通过 `$G` 函数获取 `ID` 为 "preitem" 的页面元素,并赋值给变量 `preitem`,推测这个元素可能用于展示模板相关的可选择项,比如模板的缩略图、名称等列表形式的内容,方便用户进行选择操作。 + preitem = $G("preitem"), + // 获取之前定义好的 `templates` 数组(应该是存储了多个模板信息的数组,每个元素包含模板的图片、标题、预览 HTML 代码以及完整 HTML 代码等属性),并赋值给变量 `tmps`,后续操作会基于这个数组来处理模板相关的逻辑。 tmps = templates, + // 定义变量 `currentTmp`,用于记录当前选中的模板对象,初始值为 `undefined`,在用户选择模板后会被赋值为具体的模板对象,方便后续在应用模板等操作中使用该模板的相关信息。 currentTmp; + + // `initPre` 函数用于初始化模板选择区域的展示内容,通过循环遍历 `templates` 数组,构建每个模板对应的 HTML 代码片段,最终将拼接好的 HTML 代码设置为 `preitem` 元素的 `innerHTML`,实现将所有模板以可视化的形式展示出来供用户选择。 var initPre = function () { var str = ""; - for ( var i = 0, tmp; tmp = tmps[i++]; ) { - str += '
'; + // 循环遍历 `templates` 数组,`i` 从 0 开始自增,每次循环获取当前索引对应的模板对象赋值给 `tmp`,并执行循环体中的代码逻辑。 + for (var i = 0, tmp; tmp = tmps[i++]; ) { + // 构建每个模板对应的 HTML 代码片段,创建一个类名为 "preitem" 的 `div` 元素,添加点击事件监听器,点击时调用 `pre` 函数并传入当前模板的索引(`i`),在 `div` 元素内部添加一个 `img` 图片元素,设置其 `src` 属性为模板对应的图片路径(通过拼接 "images/" 和模板对象中的 `pre` 属性获取图片文件名来组成完整路径), + // 如果模板对象有 `title` 属性(即标题),则设置图片的 `alt` 和 `title` 属性为该标题内容,用于图片的提示信息展示以及在图片无法正常显示时的替代文本显示等情况。 + str += '
'; } + // 将拼接好的包含所有模板展示项的 HTML 代码设置为 `preitem` 元素的 `innerHTML`,使得这些模板项在页面上显示出来,形成可点击选择的模板列表效果。 preitem.innerHTML = str; }; - var pre = function ( n ) { + + // `pre` 函数用于处理模板的选择操作,根据传入的模板索引 `n`,获取对应的模板对象,设置为当前选中的模板(`currentTmp`),清除之前选中模板的样式(通过 `clearItem` 函数),然后设置当前选中模板的展示样式(背景色和边框样式),并将该模板的预览 HTML 代码(`preHtml` 属性)设置到 `preview` 元素中进行展示,让用户看到所选模板的大致样子。 + var pre = function (n) { var tmp = tmps[n - 1]; currentTmp = tmp; clearItem(); - domUtils.setStyles( preitem.childNodes[n - 1], { - "background-color":"lemonChiffon", - "border":"#ccc 1px solid" - } ); - preview.innerHTML = tmp.preHtml ? tmp.preHtml : ""; + domUtils.setStyles(preitem.childNodes[n - 1], { + "background-color": "lemonChiffon", + "border": "#ccc 1px solid" + }); + preview.innerHTML = tmp.preHtml? tmp.preHtml : ""; }; + + // `clearItem` 函数用于清除所有模板选择项(`preitem` 元素下的子元素,即每个模板对应的展示 `div` 元素)的样式,将它们的背景色设置为空(即恢复默认背景色),边框设置为 1 像素宽的白色实线,用于在切换模板选择时,清除之前选中模板的突出显示样式,保持整体展示的一致性。 var clearItem = function () { var items = preitem.children; - for ( var i = 0, item; item = items[i++]; ) { - domUtils.setStyles( item, { - "background-color":"", - "border":"white 1px solid" - } ); + for (var i = 0, item; item = items[i++]; ) { + domUtils.setStyles(item, { + "background-color": "", + "border": "white 1px solid" + }); } }; + + // 为对话框(`dialog`,可能是与模板选择、应用等操作相关的弹出式对话框,用于确认操作、显示提示信息等功能)的 `onok` 事件(通常是用户点击对话框中的确认按钮时触发的事件)添加事件处理函数,在该函数内实现根据用户是否勾选保存选项来决定是否清除文档内容,以及将当前选中模板的完整 HTML 代码应用到编辑器中的逻辑。 dialog.onok = function () { - if ( !$G( "issave" ).checked ){ - me.execCommand( "cleardoc" ); + // 通过 `$G` 函数获取 `ID` 为 "issave" 的复选框元素(推测这个复选框用于控制是否保存当前文档内容等相关操作),判断其是否未被勾选(`!$G("issave").checked`),如果未勾选,则调用 `editor` 对象的 `execCommand` 方法(用于执行编辑器相关的各种命令操作),传入 "cleardoc" 命令,执行清除文档内容的操作,可能是为了在应用新模板前先清空原有内容。 + if (!$G("issave").checked) { + me.execCommand("cleardoc"); } var obj = { - html:currentTmp && currentTmp.html + html: currentTmp && currentTmp.html }; - me.execCommand( "template", obj ); + // 调用 `editor` 对象的 `execCommand` 方法,传入 "template" 命令以及包含当前选中模板完整 HTML 代码(通过 `currentTmp.html` 获取,如果 `currentTmp` 有值则取其 `html` 属性,否则为 `undefined`)的对象 `obj`,实现将所选模板的完整内容应用到编辑器中的操作,完成模板的应用功能。 + me.execCommand("template", obj); }; + + // 调用 `initPre` 函数,初始化模板选择区域的展示内容,使得页面加载时就能看到所有可供选择的模板列表。 initPre(); + // 将 `pre` 函数挂载到 `window` 对象上,使其可以在全局作用域下被访问到(虽然不太推荐这样直接暴露函数到全局,但可能是为了方便在页面的 HTML 中通过内联 `onclick` 等方式调用该函数来处理模板选择操作),名称为 `pre`。 window.pre = pre; + // 初始时默认选中索引为 2 的模板(调用 `pre` 函数并传入 2),可能是为了在页面首次加载时展示一个默认的模板示例给用户,具体默认选择哪个模板可以根据实际需求调整此处的参数。 pre(2) })(); \ No newline at end of file diff --git a/public2/ueditor/dialogs/video/video.css b/public2/ueditor/dialogs/video/video.css index 5870e7a..2cdecde 100644 --- a/public2/ueditor/dialogs/video/video.css +++ b/public2/ueditor/dialogs/video/video.css @@ -1,21 +1,50 @@ @charset "utf-8"; -.wrapper{ width: 570px;_width:575px;margin: 10px auto; zoom:1;position: relative} -.tabbody{height: 335px;} -.tabbody .panel { +/* 设置页面编码格式为 UTF-8,确保页面能正确解析和显示包含各种字符的文本内容,特别是对于中文等非 ASCII 字符的支持。这是 CSS 文件开头常见的声明,告知浏览器使用何种字符编码来解读样式表中的字符。 */ + +.wrapper{ + width: 570px; + /* 设置元素的宽度为 570 像素,用于控制该元素在页面中水平方向上占据的空间大小,从类名推测它可能是整个功能模块的外层包裹容器,用于整体布局定位。 */ + _width: 575px; + /* 这是一条针对特定浏览器(可能是 Internet Explorer 6 及以下版本,使用下划线开头的属性是一种常见的针对旧版 IE 的 hack 写法)的宽度设置,将宽度设置为 575 像素,用于解决在这些特定浏览器中可能出现的布局差异问题。 */ + margin: 10px auto; + /* 设置元素的外边距,上下外边距为 10 像素,左右外边距为自动(auto),使该元素在水平方向上能够居中对齐,常用于将模块在页面中水平居中展示的布局场景。 */ + zoom: 1; + /* 触发元素的 hasLayout 属性(同样是主要针对旧版 Internet Explorer 浏览器的一种样式设置技巧),用于解决一些在 IE 中可能出现的浮动、布局等相关的显示问题,设置为 1 表示开启这个属性,使元素具有更好的布局表现。 */ + position: relative; + /* 设置元素的定位方式为相对定位(relative),相对定位的元素会相对于它原来在文档流中的位置进行定位,方便其内部的绝对定位元素以它为参照进行更精确的布局,常用于构建复杂的页面布局结构。 */ +} + +.tabbody{ + height: 335px; + /* 定义一个名为.tabbody 的类选择器样式规则,设置元素的高度为 335 像素,从类名推测它可能是用于放置与选项卡相关内容或者具有类似结构的功能区域,用于控制该区域的整体高度大小。 */ +} + +.tabbody.panel { position: absolute; + /* 设置元素的定位方式为绝对定位(absolute),绝对定位的元素会相对于最近的已定位祖先元素进行定位(如果没有已定位的祖先元素,则相对于 body 元素),常用于将元素精确放置在页面的特定位置上。 */ width: 0; height: 0; + /* 初始将元素的宽度和高度都设置为 0,结合下面的 `overflow: hidden` 和 `display: none`,可能是一种隐藏元素且不占用页面空间的初始化设置,后续通过添加特定类名(如.focus)来改变其显示状态和尺寸大小。 */ background: #fff; + /* 设置元素的背景颜色为白色(#fff),用于定义该元素在显示时的背景色外观。 */ overflow: hidden; + /* 当元素内部的内容超出元素的尺寸范围时,隐藏超出的部分内容,避免出现内容溢出显示混乱的情况,常用于一些需要限定显示区域的元素样式设置。 */ display: none; + /* 将元素设置为不显示(隐藏状态),在页面加载初期该元素不会被展示出来,可能会根据用户的交互操作(比如点击选项卡等)来动态改变其显示状态为显示(`display: block`)。 */ } -.tabbody .panel.focus { + +.tabbody.panel.focus { width: 100%; height: 335px; display: block; + /* 当元素具有.focus 类名时(可能通过 JavaScript 动态添加该类来表示当前选中的面板等情况),设置元素的宽度为 100%(占满父元素的宽度,这里父元素应该是具有.tabbody 类的元素),高度为 335 像素(与.tabbody 类元素的高度一致),并将其显示状态设置为显示(`display: block`),使其从隐藏状态变为可见状态,用于展示相应的内容,实现类似选项卡面板切换显示的效果。 */ +} + +.tabbody.panel table td{ + vertical-align: middle; + /* 针对类名为.tabbody 的元素内部类名为.panel 的元素内部的表格(table)元素中的单元格(td)元素设置样式规则,将单元格内文本或其他内容在垂直方向上的对齐方式设置为居中对齐(vertical-align: middle),使内容在单元格内垂直居中显示,提升页面的布局美观度和可读性。 */ } -.tabbody .panel table td{vertical-align: middle;} #videoUrl { width: 490px; height: 21px; @@ -23,18 +52,55 @@ margin: 8px 5px; background: #FFF; border: 1px solid #d7d7d7; + /* 通过 ID 选择器设置 ID 为 videoUrl 的元素的样式,设置宽度为 490 像素,高度为 21 像素,行高也为 21 像素,使文本在垂直方向上能刚好占满整个元素高度,实现文本垂直居中效果;设置上下外边距为 8 像素、左右外边距为 5 像素,使元素与周围元素有一定间隔;设置背景颜色为白色(#FFF),添加 1 像素宽的浅灰色(#d7d7d7)实线边框,从命名推测它可能是用于输入视频相关链接(URL)的输入框样式设置。 */ } -#videoSearchTxt{margin-left:15px;background: #FFF;width:200px;height:21px;line-height:21px;border: 1px solid #d7d7d7;} -#searchList{width: 570px;overflow: auto;zoom:1;height: 270px;} -#searchList div{float: left;width: 120px;height: 135px;margin: 5px 15px;} -#searchList img{margin: 2px 8px;cursor: pointer;border: 2px solid #fff} /*不用缩略图*/ -#searchList p{margin-left: 10px;} + +#videoSearchTxt{ + margin-left: 15px; + background: #FFF; + width: 200px; + height: 21px; + line-height: 21px; + border: 1px solid #d7d7d7; + /* 通过 ID 选择器设置 ID 为 videoSearchTxt 的元素的样式,设置左边距为 15 像素,使元素相对于左侧有一定间隔;设置背景颜色为白色(#FFF),宽度为 200 像素,高度为 21 像素,行高为 21 像素用于文本垂直居中;添加 1 像素宽的浅灰色(#d7d7d7)实线边框,从命名推测它可能是用于输入视频搜索相关文本的输入框样式设置。 */ +} + +#searchList{ + width: 570px; + overflow: auto; + zoom: 1; + height: 270px; + /* 通过 ID 选择器设置 ID 为 searchList 的元素的样式,设置宽度为 570 像素(可能与外层包裹元素.wrapper 的宽度一致,用于占满相应的布局空间),高度为 270 像素,用于控制该元素的尺寸大小;设置 `overflow: auto`,当内部内容超出这个高度时,会自动出现垂直滚动条,方便查看所有内容;设置 `zoom: 1`,同样可能是针对旧版 IE 浏览器解决布局相关问题,从命名推测它可能是用于展示视频搜索结果列表的区域样式设置。 */ +} + +#searchList div{ + float: left; + width: 120px; + height: 135px; + margin: 5px 15px; + /* 通过 ID 选择器设置 ID 为 searchList 的元素内部的 div 元素的样式,设置元素向左浮动(float: left),使其能够水平排列;设置宽度为 120 像素,高度为 135 像素,确定元素的尺寸大小;设置上下外边距为 5 像素、左右外边距为 15 像素,用于控制各 div 元素之间的间隔距离,从结构和命名推测这些 div 元素可能是用于展示单个视频搜索结果相关信息(如缩略图、标题等)的容器样式设置。 */ +} + +#searchList img{ + margin: 2px 8px; + cursor: pointer; + border: 2px solid #fff; + /* 通过 ID 选择器设置 ID 为 searchList 的元素内部的 img 图片元素的样式,设置上下外边距为 2 像素、左右外边距为 8 像素,用于控制图片与周围元素的间隔距离;将鼠标指针样式(cursor)设置为指针形状(cursor: pointer),提示用户该图片可点击交互;设置图片边框为 2 像素宽的白色实线(border: 2px solid #fff),从命名推测这些图片可能是视频的缩略图,设置样式使其具有一定的交互效果和外观表现。 */ +} + +#searchList p{ + margin-left: 10px; + /* 通过 ID 选择器设置 ID 为 searchList 的元素内部的 p 段落元素的样式,设置左边距为 10 像素,使段落文本相对于左侧有一定的间隔距离,用于统一该区域内段落文本的布局样式。 */ +} + #videoType{ width: 65px; height: 23px; line-height: 22px; border: 1px solid #d7d7d7; + /* 通过 ID 选择器设置 ID 为 videoType 的元素的样式,设置宽度为 65 像素,高度为 23 页像素,行高为 22 像素,用于控制文本在垂直方向上的对齐情况;添加 1 像素宽的浅灰色(#d7d7d7)实线边框,从命名推测它可能是用于选择视频类型的下拉框或其他类似输入控件的样式设置。 */ } + #videoSearchBtn,#videoSearchReset{ /*width: 80px;*/ height: 25px; @@ -43,6 +109,7 @@ border: 1px solid #d7d7d7; cursor: pointer; padding: 0 5px; + /* 通过 ID 选择器设置 ID 为 videoSearchBtn 和 videoSearchReset 的元素(可能是两个按钮元素)的样式,原本设置的宽度(width)被注释掉了,高度为 25 像素,行高也为 25 像素,使文本在按钮内垂直居中;设置背景颜色为浅灰色(#eee),添加 1 像素宽的浅灰色(#d7d7d7)实线边框;将鼠标指针样式(cursor)设置为指针形状(cursor: pointer),提示用户可点击操作;设置左右内边距为 5 像素,用于控制按钮内文本与边框的间隔距离,从命名推测这两个按钮可能分别用于执行视频搜索和重置搜索条件等操作的按钮样式设置。 */ } diff --git a/public2/ueditor/dialogs/video/video.html b/public2/ueditor/dialogs/video/video.html index 5007882..863f4b1 100644 --- a/public2/ueditor/dialogs/video/video.html +++ b/public2/ueditor/dialogs/video/video.html @@ -1,86 +1,124 @@ + "http://www.w3.org/TR/html4/loose.dtd"> - + + + + + -
-
-
- - -
-
-
-
-
-
-
- - - - -
-
-
- -
-
-
+
+ +
+ +
+ + + + +
-
-
-
-
-
- 0% - -
-
-
-
+
+ +
+ +
+ +
+ +
+ +
+ + + + + + + + + +
+
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+ +
+ + 0% + + + +
+ +
+ +
+ +
+ +
-
-
-
-
+
+ +
+ +
+ +
+
    + +
  • + +
-
    -
  • -
-
-
-
- - - - -
-
-
- -
-
+
+ +
+ + + + +
+
+
+ +
+
+
-
- - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/public2/ueditor/dialogs/video/video.js b/public2/ueditor/dialogs/video/video.js index 681a945..5370ddf 100644 --- a/public2/ueditor/dialogs/video/video.js +++ b/public2/ueditor/dialogs/video/video.js @@ -6,32 +6,47 @@ * To change this template use File | Settings | File Templates. */ -(function(){ +// 创建一个自执行函数,用于封装相关变量和函数,避免全局变量污染,使得这些代码逻辑相对独立,内部定义的变量和函数不会直接暴露在全局作用域下,除非特意通过 `window` 对象等进行挂载。 +(function () { + // 创建一个名为 `video` 的空对象,从命名推测它可能用于存储与视频相关的各种属性、方法等信息,后续可能会不断添加属性来记录视频相关的状态或操作逻辑,不过目前还未具体定义其内部内容。 var video = {}, + // 创建一个名为 `uploadVideoList` 的空数组,用于存储上传视频相关的信息列表,比如已选择准备上传的视频文件信息、上传中的视频相关状态等,具体存储内容依赖后续代码逻辑中对其的操作。 uploadVideoList = [], + // 创建一个名为 `isModifyUploadVideo` 的布尔变量,初始值为 `false`,用于标记是否正在修改已上传的视频相关信息,在后续编辑视频等操作中会根据实际情况改变该值,以便进行不同的逻辑处理。 isModifyUploadVideo = false, + // 创建一个名为 `uploadFile` 的变量,从命名推测它可能用于存储正在上传的文件相关信息,不过目前还未赋值,具体用途依赖后续代码对其的使用情况。 uploadFile; - window.onload = function(){ + // 为 `window` 对象的 `onload` 事件(该事件会在页面所有资源(如图片、脚本、样式表等)加载完成后触发)添加事件处理函数,在页面加载完成时执行一系列初始化操作,包括设置输入框焦点、初始化选项卡、初始化视频相关功能以及初始化上传相关功能等。 + window.onload = function () { + // 调用 `$focus` 函数(可能是自定义的用于设置页面元素焦点的函数,具体功能依赖其内部实现),将焦点设置到 `ID` 为 "videoUrl" 的页面元素上,通常用于让用户在页面加载后能直接在这个输入框进行操作,比如输入视频链接等。 $focus($G("videoUrl")); + // 调用 `initTabs` 函数,用于初始化页面中的选项卡相关功能,比如设置选项卡的点击切换逻辑、切换时对应的样式变化等操作,使选项卡能正常工作,切换不同的视频相关功能页面(如插入视频和上传视频等不同面板的切换)。 initTabs(); + // 调用 `initVideo` 函数,用于初始化视频相关的各种功能,比如创建对齐按钮、添加视频链接变化监听器、添加确认按钮点击监听器等操作,同时也处理编辑视频时相关信息的初始化工作,用于构建完整的视频操作功能逻辑。 initVideo(); + // 调用 `initUpload` 函数(此处未展示该函数具体实现,但从命名推测是用于初始化视频上传相关的功能,比如设置上传按钮点击事件、文件选择逻辑、上传进度显示等操作),实现上传功能的初始化设置。 initUpload(); }; /* 初始化tab标签 */ - function initTabs(){ + function initTabs() { + // 通过 `$G` 函数(可能是自定义的用于获取页面元素的函数,根据传入的 `ID` 等标识来获取对应的 DOM 元素)获取 `ID` 为 "tabHeads" 的页面元素,并获取其所有子元素(即选项卡头部的各个标签元素),存储在 `tabs` 变量中,后续通过循环遍历这些子元素来添加点击事件监听器等操作。 var tabs = $G('tabHeads').children; for (var i = 0; i < tabs.length; i++) { + // 为每个选项卡头部标签元素(`tabs[i]`)添加点击事件监听器,当点击某个选项卡标签时,执行下面的函数逻辑,实现选项卡的切换效果以及相关样式的更新等操作。 domUtils.on(tabs[i], "click", function (e) { var j, bodyId, target = e.target || e.srcElement; for (j = 0; j < tabs.length; j++) { + // 获取每个选项卡头部标签元素的 `data-content-id` 属性值(该属性在 HTML 中设置,用于关联对应的选项卡内容面板的 `ID`),存储在 `bodyId` 变量中,用于后续根据点击的标签找到对应的内容面板元素进行操作。 bodyId = tabs[j].getAttribute('data-content-id'); - if(tabs[j] == target){ + if (tabs[j] == target) { + // 如果当前循环到的选项卡头部标签元素(`tabs[j]`)就是被点击的目标元素(`target`),则调用 `domUtils.addClass` 函数(可能是自定义的用于添加类名到元素上的工具函数,通过操作元素的 `classList` 属性等来添加类名,用于改变元素的样式等表现),为该标签元素添加 "focus" 类名,用于改变其样式(比如突出显示,表示当前选中状态);同时也为对应的内容面板元素(通过 `$G(bodyId)` 获取)添加 "focus" 类名,使其显示出来(假设在 CSS 中通过 ".focus" 类设置了显示相关的样式),实现选项卡切换到对应面板的效果。 domUtils.addClass(tabs[j], 'focus'); domUtils.addClass($G(bodyId), 'focus'); - }else { + } else { + // 如果当前选项卡头部标签元素不是被点击的目标元素,则调用 `domUtils.removeClasses` 函数(可能是自定义的用于移除元素类名的工具函数,与 `addClass` 对应,通过操作 `classList` 属性等来移除类名,恢复元素原来的样式等表现),移除该标签元素的 "focus" 类名,取消突出显示等样式;同时也移除对应的内容面板元素的 "focus" 类名,使其隐藏(如果在 CSS 中通过 ".focus" 类控制显示隐藏),实现切换其他选项卡时当前选项卡相关元素恢复默认状态的效果。 domUtils.removeClasses(tabs[j], 'focus'); domUtils.removeClasses($G(bodyId), 'focus'); } @@ -40,33 +55,42 @@ } } - function initVideo(){ - createAlignButton( ["videoFloat", "upload_alignment"] ); + function initVideo() { + // 调用 `createAlignButton` 函数(具体功能依赖其内部实现,但从命名推测是用于创建与视频对齐相关的按钮,比如控制视频在页面中水平对齐方式的按钮等),传入一个包含两个元素的数组 ["videoFloat", "upload_alignment"],可能表示要为这两个不同的对齐相关元素创建对应的按钮,用于视频展示时的对齐操作设置。 + createAlignButton(["videoFloat", "upload_alignment"]); + // 调用 `addUrlChangeListener` 函数(可能是用于添加对视频链接(URL)输入框的内容变化监听器,当用户输入或修改视频链接时触发相应的逻辑,比如实时验证链接有效性、更新相关提示信息等操作),传入 `ID` 为 "videoUrl" 的页面元素(即视频链接输入框),实现对视频链接变化的监听功能。 addUrlChangeListener($G("videoUrl")); - addOkListener(); - - //编辑视频时初始化相关信息 - (function(){ - var img = editor.selection.getRange().getClosedNode(),url; - if(img && img.className){ + // 调用 `addOkListener` 函数(可能是用于添加确认按钮(比如保存视频设置、应用视频插入等相关操作的确认按钮)的点击事件监听器,当用户点击确认按钮时执行相应的业务逻辑,比如将视频相关设置应用到编辑器中、保存视频配置等操作),用于添加相关的点击事件处理逻辑。 + + // 以下是一个自执行函数,用于在编辑视频时初始化相关信息,比如获取当前选中视频的链接、尺寸、对齐方式等信息,并设置到对应的页面输入框等元素中,方便用户进行编辑修改操作,同时根据视频类型等情况设置相应的状态标记(如 `isModifyUploadVideo`)。 + (function () { + // 通过 `editor` 对象(可能是整个应用中与文本编辑相关的核心对象,包含了各种编辑操作的方法、属性等,前面应该有定义或者引入相应的代码)的 `selection` 属性(可能用于获取当前文本选择相关的信息)的 `getRange` 方法(可能用于获取选择范围相关的对象)的 `getClosedNode` 方法(可能用于获取选择范围对应的节点元素,比如选中的图片等元素)获取当前选中的节点元素(假设是视频相关的图片元素),存储在 `img` 变量中;同时定义一个变量 `url`,用于后续存储视频的链接信息,但目前未赋值。 + var img = editor.selection.getRange().getClosedNode(), url; + if (img && img.className) { + // 判断获取到的节点元素(`img`)是否存在且有 `className` 属性(用于判断是否是特定类型的元素,通过类名来区分,比如判断是否是模拟视频元素或者已上传视频元素等),如果满足条件则进入下面的逻辑判断。 var hasFakedClass = (img.className == "edui-faked-video"), - hasUploadClass = img.className.indexOf("edui-upload-video")!=-1; - if(hasFakedClass || hasUploadClass) { + hasUploadClass = img.className.indexOf("edui-upload-video")!= -1; + if (hasFakedClass || hasUploadClass) { + // 如果节点元素的类名是 "edui-faked-video"(可能表示是一种模拟的视频元素,比如通过占位符等方式模拟视频展示效果)或者类名中包含 "edui-upload-video"(可能表示是已上传的视频元素),则执行以下操作。 + // 将节点元素(`img`)的 `_url` 属性值(假设在 HTML 中通过自定义属性存储了视频链接信息)获取出来,赋值给 `url` 变量,然后将该值设置到 `ID` 为 "videoUrl" 的输入框(视频链接输入框)的 `value` 属性中,实现将视频链接显示在输入框中供用户编辑修改;同时将节点元素的 `width` 和 `height` 属性值(视频的宽度和高度信息)分别设置到 `ID` 为 "videoWidth" 和 "videoHeight" 的输入框中,用于展示视频的尺寸信息,方便用户进行编辑。 $G("videoUrl").value = url = img.getAttribute("_url"); $G("videoWidth").value = img.width; $G("videoHeight").value = img.height; - var align = domUtils.getComputedStyle(img,"float"), - parentAlign = domUtils.getComputedStyle(img.parentNode,"text-align"); - updateAlignButton(parentAlign==="center"?"center":align); + // 通过 `domUtils.getComputedStyle` 函数(可能是自定义的用于获取元素计算后的样式信息的函数,类似于浏览器原生的 `window.getComputedStyle` 方法,用于获取元素实际应用的样式属性值)获取节点元素(`img`)的 `float` 属性值(用于获取视频的浮动对齐方式,比如左对齐、右对齐等),存储在 `align` 变量中;同时获取节点元素的父元素的 `text-align` 属性值(可能用于获取父元素中对文本的对齐方式,在某些情况下也可能影响视频的对齐表现),存储在 `parentAlign` 变量中,然后调用 `updateAlignButton` 函数(具体功能依赖其内部实现,但从命名推测是用于更新对齐按钮的状态等操作,使其与获取到的对齐方式信息一致),传入根据对齐方式判断后的结果(如果父元素文本对齐方式是 "center" 则传入 "center",否则传入 `align` 的值),实现根据视频实际对齐情况更新对齐按钮显示状态的功能。 + var align = domUtils.getComputedStyle(img, "float"), + parentAlign = domUtils.getComputedStyle(img.parentNode, "text-align"); + updateAlignButton(parentAlign === "center"? "center" : align); } - if(hasUploadClass) { + if (hasUploadClass) { + // 如果节点元素的类名中包含 "edui-upload-video"(即判断为已上传的视频元素),则将 `isModifyUploadVideo` 变量设置为 `true`,标记当前正在修改已上传的视频相关信息,方便后续在保存、应用等操作中进行不同的逻辑处理。 isModifyUploadVideo = true; } } + // 调用 `createPreviewVideo` 函数(具体功能依赖其内部实现,但从命名推测是用于创建视频的预览相关功能,比如根据视频链接等信息在页面上展示视频的预览画面等操作),传入获取到的视频链接 `url`,实现视频预览功能的初始化设置,让用户能看到视频的大致样子方便编辑操作。 createPreviewVideo(url); })(); } - +})(); /** * 监听确认和取消两个按钮事件,用户执行插入或者清空正在播放的视频实例操作 */ diff --git a/public2/ueditor/dialogs/webapp/webapp.html b/public2/ueditor/dialogs/webapp/webapp.html index 1614377..77a2c8f 100644 --- a/public2/ueditor/dialogs/webapp/webapp.html +++ b/public2/ueditor/dialogs/webapp/webapp.html @@ -2,50 +2,84 @@ - + + + +
+
+
diff --git a/public2/ueditor/dialogs/wordimage/wordimage.html b/public2/ueditor/dialogs/wordimage/wordimage.html index 670db71..90af3e9 100644 --- a/public2/ueditor/dialogs/wordimage/wordimage.html +++ b/public2/ueditor/dialogs/wordimage/wordimage.html @@ -1,108 +1,203 @@ + "http://www.w3.org/TR/html4/loose.dtd"> - + + + +
+
+ +
+
+
- + +
+ : +
-
+
+ + diff --git a/public2/ueditor/dialogs/wordimage/wordimage.js b/public2/ueditor/dialogs/wordimage/wordimage.js index 98f3a22..e17c3cb 100644 --- a/public2/ueditor/dialogs/wordimage/wordimage.js +++ b/public2/ueditor/dialogs/wordimage/wordimage.js @@ -6,92 +6,126 @@ * To change this template use File | Settings | File Templates. */ - - +// 定义一个名为 `wordImage` 的空对象,从后续代码来看,它可能用于聚合与图片相关的各种方法、属性等,作为图片功能模块的一个主要对象,通过向其添加不同的函数来实现具体的图片操作功能。 var wordImage = {}; + +// 以下原本是一个自执行函数的开头,但被注释掉了,若取消注释则可形成一个独立的作用域,避免全局变量污染。不过目前代码整体处于全局作用域下,定义的变量和函数在外部是可访问的(除了在函数内部通过闭包等方式限制访问的局部变量)。 //(function(){ + +// 通过 `baidu.g` 函数(可能是自定义的用于获取页面元素的函数,依赖于 `baidu` 对象,根据传入的 `ID` 等标识来获取对应的 DOM 元素,类似于 `document.getElementById` 的功能,但可能有更多自定义的逻辑处理)获取页面元素,这里获取了两个变量,`g` 可能用于后续多次获取元素的操作,更方便简洁;`flashContainer` 则专门用于指代某个与 Flash 相关的容器元素(从命名推测可能是用于承载 Flash 图片上传组件的元素,后续代码也体现了这一点),不过目前还未赋值,等待后续使用时再确定具体对应的元素。 var g = baidu.g, - flashObj,flashContainer; + flashObj, flashContainer; -wordImage.init = function(opt, callbacks) { - showLocalPath("localPath"); - //createCopyButton("clipboard","localPath"); - createFlashUploader(opt, callbacks); - addUploadListener(); - addOkListener(); +// 为 `wordImage` 对象添加 `init` 方法,用于初始化图片相关的各种功能,通过传入配置对象 `opt` 和回调函数对象 `callbacks`,在函数内部调用多个其他函数来实现诸如展示本地路径、创建 Flash 上传组件、添加上传事件监听以及添加确认按钮点击事件监听等操作,完成图片功能模块的初始化流程。 +wordImage.init = function (opt, callbacks) { + showLocalPath("localPath"); + // 调用 `showLocalPath` 函数,传入 `"localPath"` 参数,用于展示本地图片路径相关信息,将相应的路径显示在 `ID` 为 `localPath` 的页面元素(可能是一个输入框等用于展示路径的元素)中,方便用户查看。 + //createCopyButton("clipboard","localPath"); + // 这行代码被注释掉了,原本应该是调用 `createCopyButton` 函数,传入 `"clipboard"` 和 `"localPath"` 参数,从命名推测可能是用于创建一个复制按钮,关联到 `ID` 为 `clipboard` 的元素,并且与 `localPath` 相关(可能是用于复制 `localPath` 显示的本地路径内容等功能),不过目前暂未执行此功能。 + createFlashUploader(opt, callbacks); + // 调用 `createFlashUploader` 函数,传入配置对象 `opt` 和回调函数对象 `callbacks`,用于创建 Flash 图片上传组件,进行相关的配置设置以及初始化操作,使其能够正常显示并实现图片上传功能。 + addUploadListener(); + // 调用 `addUploadListener` 函数,用于添加图片上传相关的事件监听,比如点击上传按钮时触发的上传操作逻辑等,确保用户操作能正确响应并执行相应的上传流程。 + addOkListener(); + // 调用 `addOkListener` 函数,用于添加确认按钮(可能是在完成图片上传等操作后,用于确认应用这些图片相关设置的按钮)点击事件的监听,在点击确认按钮时执行相应的业务逻辑,比如将上传后的图片信息应用到编辑器中的图片元素上,更新图片的链接、属性等内容。 }; -function hideFlash(){ +// `hideFlash` 函数用于隐藏 Flash 相关的元素并清理相关的数据或内容,将 `flashObj` 设置为 `null`(可能用于释放相关资源或者标记 Flash 对象已不存在等情况),同时清空 `flashContainer` 元素的 `innerHTML`(即将其内部的子元素全部移除,实现清空容器内容的效果,比如隐藏或移除 Flash 上传组件的显示界面等)。 +function hideFlash() { flashObj = null; flashContainer.innerHTML = ""; } + +// `addOkListener` 函数用于为对话框(`dialog`,可能是与图片操作相关的弹出式对话框,用于确认操作、显示提示信息等功能)的 `onok` 事件(通常是用户点击对话框中的确认按钮时触发的事件)和 `oncancel` 事件(用户点击取消按钮时触发的事件)添加事件处理函数。 function addOkListener() { - dialog.onok = function() { - if (!imageUrls.length) return; - var urlPrefix = editor.getOpt('imageUrlPrefix'), - images = domUtils.getElementsByTagName(editor.document,"img"); + dialog.onok = function () { + if (!imageUrls.length) return; + // 判断 `imageUrls` 数组(该数组用于保存从服务器返回的图片信息,在其他地方会将上传成功后的图片相关数据添加到这个数组中)的长度是否为 0,如果为空则直接返回,不执行后续操作,意味着只有当有上传成功的图片信息时才进行下面的处理逻辑。 + var urlPrefix = editor.getOpt('imageUrlPrefix'), + images = domUtils.getElementsByTagName(editor.document, "img"); + // 通过 `editor` 对象(可能是整个应用中与文本编辑相关的核心对象,包含了各种编辑操作的方法、属性等)的 `getOpt` 方法(用于获取之前设置的配置选项的值)获取名为 `imageUrlPrefix` 的配置选项的值,赋值给 `urlPrefix` 变量,这个值可能是图片 URL 的前缀部分,用于拼接完整的图片链接;然后通过 `domUtils.getElementsByTagName` 函数(可能是自定义的用于获取指定元素下的特定标签元素的函数,类似于浏览器原生的 `document.getElementsByTagName` 方法,但基于 `editor.document`(可能是编辑器中的文档对象,用于操作编辑器内的元素)进行查找)获取文档中所有的 `` 图片元素,存储在 `images` 变量中,后续会遍历这些图片元素来更新它们的相关属性。 editor.fireEvent('saveScene'); - for (var i = 0,img; img = images[i++];) { - var src = img.getAttribute("word_img"); - if (!src) continue; - for (var j = 0,url; url = imageUrls[j++];) { - if (src.indexOf(url.original.replace(" ","")) != -1) { - img.src = urlPrefix + url.url; - img.setAttribute("_src", urlPrefix + url.url); //同时修改"_src"属性 - img.setAttribute("title",url.title); - domUtils.removeAttributes(img, ["word_img","style","width","height"]); - editor.fireEvent("selectionchange"); - break; - } - } - } + // 调用 `editor` 对象的 `fireEvent` 方法(可能用于触发编辑器中定义的特定事件,这里触发 `saveScene` 事件,具体该事件对应的处理逻辑依赖于编辑器中对其的定义,可能用于保存当前场景、状态等相关操作,此处可能是在更新图片前先保存一下相关状态)。 + for (var i = 0, img; img = images[i++];) { + var src = img.getAttribute("word_img"); + if (!src) continue; + // 遍历获取到的所有图片元素,获取每个图片元素的 `word_img` 属性值(从命名推测可能是在图片上传前用于临时标记图片的某个属性,比如原始路径或者临时的唯一标识等),如果该属性不存在(值为 `null` 或者 `undefined`)则跳过当前循环,继续下一个图片元素的处理,意味着只处理带有 `word_img` 属性的图片元素。 + for (var j = 0, url; url = imageUrls[j++];) { + if (src.indexOf(url.original.replace(" ", ""))!= -1) { + // 内层循环遍历 `imageUrls` 数组中的每个图片信息对象(`url`),将图片元素的 `word_img` 属性值(`src`)与图片信息对象中的 `original` 属性值(去除空格后)进行比较(通过 `indexOf` 方法判断是否包含),如果找到匹配的,则执行以下更新图片元素属性的操作。 + img.src = urlPrefix + url.url; + // 将图片元素的 `src` 属性(用于设置图片的链接地址)更新为 `urlPrefix`(前面获取的图片 URL 前缀)与图片信息对象中的 `url` 属性(完整的图片链接地址的一部分,与 `urlPrefix` 拼接后形成完整地址)拼接后的字符串,实现将图片链接替换为上传后服务器返回的正确链接地址。 + img.setAttribute("_src", urlPrefix + url.url); //同时修改"_src"属性 + // 同时为图片元素添加 `_src` 属性(可能是用于备份原始 `src` 属性值或者有其他相关用途,具体依赖应用中的逻辑),并设置其值与 `src` 属性相同,也是拼接后的完整图片链接地址。 + img.setAttribute("title", url.title); + // 为图片元素添加 `title` 属性,设置其值为图片信息对象中的 `title` 属性值(可能是图片的标题、描述等相关文字信息,用于在鼠标悬停等情况下显示提示信息)。 + domUtils.removeAttributes(img, ["word_img", "style", "width", "height"]); + // 通过 `domUtils.removeAttributes` 函数(可能是自定义的用于移除元素指定属性的函数)移除图片元素的 `word_img`、`style`(可能是之前设置的一些临时样式属性等)、`width` 和 `height`(可能是上传前的图片原始尺寸属性,现在更新链接后可能不需要了或者后续会根据新图片重新计算尺寸等情况)属性,清理不必要的属性设置。 + editor.fireEvent("selectionchange"); + // 调用 `editor` 对象的 `fireEvent` 方法,触发 `selectionchange` 事件(可能用于通知编辑器图片选择等相关状态发生了变化,以便编辑器进行相应的界面更新、其他逻辑处理等操作,比如重新渲染图片所在区域等)。 + break; + // 找到匹配的图片信息对象并更新完当前图片元素的属性后,通过 `break` 跳出内层循环,继续处理下一个图片元素,避免重复匹配和不必要的循环比较。 + } + } + } editor.fireEvent('saveScene'); + // 再次触发 `saveScene` 事件,可能是在完成所有图片元素属性更新后,再次保存一下最终的场景、状态等信息,确保数据的完整性和一致性。 hideFlash(); - }; - dialog.oncancel = function(){ + // 调用 `hideFlash` 函数,隐藏 Flash 相关元素并清理其内容,比如在图片处理完成后,隐藏或移除 Flash 上传组件的显示界面等,完成整个操作流程后的清理工作。 + }; + dialog.oncancel = function () { hideFlash(); } + // 为对话框的 `oncancel` 事件添加事件处理函数,当用户点击取消按钮时,直接调用 `hideFlash` 函数,隐藏 Flash 相关元素并清理其内容,撤销可能正在进行的图片上传操作或者清理已显示的相关界面元素等情况。 } /** * 绑定开始上传事件 */ function addUploadListener() { - g("upload").onclick = function () { - flashObj.upload(); - this.style.display = "none"; - }; + g("upload").onclick = function () { + flashObj.upload(); + this.style.display = "none"; + // 通过 `g` 函数获取 `ID` 为 `upload` 的页面元素(可能是一个上传按钮元素),并为其添加点击事件监听器,当用户点击该按钮时,调用 `flashObj`(可能是 Flash 上传组件对应的对象,在 `createFlashUploader` 函数中实例化创建的)的 `upload` 方法,触发图片上传操作;然后将按钮自身的 `style.display` 属性设置为 `"none"`,隐藏该上传按钮,可能是为了避免用户重复点击或者表示上传正在进行中不需要再次点击等情况。 + }; } function showLocalPath(id) { + // 以下代码用于展示本地图片路径相关信息,根据不同的情况(单张编辑或者多张图片相关情况)来确定要显示的路径内容,并将其设置到对应的页面元素(通过传入的 `id` 参数指定的元素,通常是一个输入框用于展示路径)中。 //单张编辑 var img = editor.selection.getRange().getClosedNode(); var images = editor.execCommand('wordimage'); - if(images.length==1 || img && img.tagName == 'IMG'){ + if (images.length == 1 || img && img.tagName == 'IMG') { g(id).value = images[0]; return; } - var path = images[0]; - var leftSlashIndex = path.lastIndexOf("/")||0, //不同版本的doc和浏览器都可能影响到这个符号,故直接判断两种 - rightSlashIndex = path.lastIndexOf("\\")||0, - separater = leftSlashIndex > rightSlashIndex ? "/":"\\" ; - - path = path.substring(0, path.lastIndexOf(separater)+1); - g(id).value = path; + // 首先通过 `editor` 对象的 `selection` 属性(用于获取当前文本选择相关的信息)的 `getRange` 方法(获取选择范围相关的对象)的 `getClosedNode` 方法(获取选择范围对应的节点元素,比如选中的图片等元素)获取当前选中的节点元素,存储在 `img` 变量中;然后通过 `editor` 对象执行 `wordimage` 命令(具体 `wordimage` 命令的功能依赖编辑器中对其的定义,可能是获取相关图片信息等操作)获取图片相关的信息,存储在 `images` 数组中。如果获取到的 `images` 数组长度为 1(表示只有一张图片相关信息)或者 `img` 存在且其标签名是 ``(即选中了一张图片),则通过 `g` 函数获取 `ID` 为 `id` 的页面元素(比如一个输入框),并将 `images[0]`(第一张图片相关信息,可能是路径等内容)设置为该元素的 `value` 属性值,完成路径展示后直接返回,结束函数执行。 + var path = images[0]; + var leftSlashIndex = path.lastIndexOf("/") || 0, //不同版本的doc和浏览器都可能影响到这个符号,故直接判断两种 + rightSlashIndex = path.lastIndexOf("\\") || 0, + separater = leftSlashIndex > rightSlashIndex? "/": "\\"; + // 如果不满足上述单张图片的情况,则获取 `images` 数组中的第一个元素(可能是一个包含路径信息的字符串等),赋值给 `path` 变量,然后分别查找路径字符串中最后一次出现斜杠(`/`)和反斜杠(`\`)的索引位置,存储在 `leftSlashIndex` 和 `rightSlashIndex` 变量中,通过比较这两个索引大小,确定实际的路径分隔符(选择最后出现的那个斜杠或反斜杠作为分隔符,存储在 `separater` 变量中),用于后续截取正确的路径部分。 + path = path.substring(0, path.lastIndexOf(separater) + 1); + g(id).value = path; + // 使用 `substring` 方法截取 `path` 字符串,从开头截取到最后一次出现分隔符的位置(加上 1 是包含分隔符本身),得到正确的路径前缀部分(比如文件夹路径部分),然后将其设置到通过 `g` 函数获取的 `ID` 为 `id` 的页面元素(如输入框)的 `value` 属性中,实现展示本地图片路径的功能。 } function createFlashUploader(opt, callbacks) { + // 该函数用于创建 Flash 图片上传组件,进行相关的配置设置、处理国际化相关的图片资源地址编码问题,并实例化 Flash 上传组件对象,使其能够正常显示并实现图片上传功能。 //由于lang.flashI18n是静态属性,不可以直接进行修改,否则会影响到后续内容 - var i18n = utils.extend({},lang.flashI18n); + var i18n = utils.extend({}, lang.flashI18n); + // 通过 `utils.extend` 函数(可能是自定义的用于合并对象属性的函数,将第一个对象的属性复制到第二个对象上,如果有同名属性则覆盖,这里将 `lang.flashI18n` 的属性复制到一个新的空对象 `i18n` 上,用于获取一份原始的国际化相关属性的副本,避免直接修改原始的静态属性,影响其他地方的使用)创建一个新对象 `i18n`,复制了 `lang.flashI18n`(可能是存储了 Flash 相关的国际化文本信息、图片资源路径等属性的对象,用于根据不同语言环境展示相应内容)的属性,后续可以对这个副本进行修改操作。 //处理图片资源地址的编码,补全等问题 - for(var i in i18n){ - if(!(i in {"lang":1,"uploadingTF":1,"imageTF":1,"textEncoding":1}) && i18n[i]){ + for (var i in i18n) { + if (!(i in {"lang": 1, "uploadingTF": 1, "imageTF": 1, "textEncoding": 1}) && i18n[i]) { i18n[i] = encodeURIComponent(editor.options.langPath + editor.options.lang + "/images/" + i18n[i]); } } - opt = utils.extend(opt,i18n,false); - var option = { - createOptions:{ + // 遍历 `i18n` 对象的属性,对于除了 `lang`、`uploadingTF`、`imageTF`、`textEncoding` 这几个特定属性之外的其他属性(通过判断属性名是否在一个特定的对象中存在来筛选),并且属性值不为 `null` 或者 `undefined` 的情况,使用 `encodeURIComponent` 函数(JavaScript 内置函数,用于对 URI 组件进行编码,将特殊字符转换为对应的编码格式,确保在 URL 等场景中能正确传输和解析)对其进行编码处理,编码的内容是将 `editor.options.langPath`(可能是语言相关的路径前缀)、`editor.options.lang`(当前使用的语言标识)、`"/images/"`(固定的图片资源路径部分)以及属性值(原始的图片资源相关的文件名等信息)拼接后的字符串进行编码,这样处理后的属性值可以正确地在 Flash 上传组件中使用,避免因特殊字符等问题导致资源加载错误。 + opt = utils.extend(opt, i18n, false); + // 再次使用 `utils.extend` 函数,将处理好的 `i18n` 对象的属性合并到传入的 `opt` 对象(可能是用于配置 Flash 上传组件的各种参数的对象,包含了如上传地址、文件格式限制、尺寸限制等相关属性)上,不过这里第三个参数 `false` 不太明确其具体作用(可能是控制合并的方式,比如是否深度合并等情况,需要查看 `utils.extend` 函数的具体实现),完成对 `opt` 对象的配置参数更新,添加了国际化相关的处理后的属性内容。 + var option = { + createOptions: { id:'flash', url:opt.flashUrl, width:opt.width, -- 2.34.1