Repository: MrXujiang/h5-Dooring Branch: master Commit: 85a184a72bd9 Files: 236 Total size: 1.6 MB Directory structure: gitextract_819mm14l/ ├── .github/ │ ├── FUNDING.yml │ └── ISSUE_TEMPLATE/ │ └── custom.md ├── .gitignore ├── .umirc.ts ├── .vscode/ │ └── settings.json ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── SECURITY.md ├── doc/ │ ├── .vuepress/ │ │ ├── config.js │ │ ├── templates/ │ │ │ └── dev.html │ │ └── theme/ │ │ ├── enhanceApp.js │ │ ├── global-components/ │ │ │ └── Home.vue │ │ ├── index.js │ │ ├── layouts/ │ │ │ └── Layout.vue │ │ └── styles/ │ │ ├── _layout.scss │ │ ├── _reset.scss │ │ ├── main.scss │ │ └── palette.styl │ ├── README.md │ └── zh/ │ └── guide/ │ ├── README.md │ ├── building.md │ ├── componentDev/ │ │ ├── DSLAnalysis.md │ │ ├── componentStructure.md │ │ └── dynamicLoading.md │ ├── deployDev/ │ │ ├── api.md │ │ ├── deploy.md │ │ ├── deploy_v6.md │ │ ├── dir.md │ │ ├── form.md │ │ ├── https.md │ │ ├── log.md │ │ └── oss.md │ ├── directoryStructure.md │ ├── functionRealization/ │ │ ├── download.md │ │ ├── machinePreview.md │ │ ├── pagePreview.md │ │ ├── revocation.md │ │ ├── saveJson.md │ │ ├── screenshot.md │ │ └── templateLibrary.md │ ├── introduced.md │ └── startedQuickly.md ├── package.json ├── readme.md ├── server.js ├── src/ │ ├── app.tsx │ ├── components/ │ │ ├── Calibration/ │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── ErrorBundaries/ │ │ │ └── index.tsx │ │ ├── FormComponents/ │ │ │ ├── CardPicker/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── Color/ │ │ │ │ └── index.tsx │ │ │ ├── DataList/ │ │ │ │ ├── editorModal.tsx │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── FormItems/ │ │ │ │ ├── EditorModal.tsx │ │ │ │ ├── FormItems.tsx │ │ │ │ ├── formItems.less │ │ │ │ └── index.tsx │ │ │ ├── MutiText/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── Pos/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── Table/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── Upload/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── XEditor/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ └── types.ts │ │ ├── LoadingCp/ │ │ │ └── index.tsx │ │ └── Zan/ │ │ ├── index.less │ │ └── index.tsx │ ├── core/ │ │ ├── DynamicEngine.tsx │ │ ├── index.ts │ │ └── renderer/ │ │ ├── FormRender.tsx │ │ ├── ViewRender.tsx │ │ └── viewRender.less │ ├── global.css │ ├── layouts/ │ │ ├── index.less │ │ └── index.tsx │ ├── materials/ │ │ ├── base/ │ │ │ ├── Carousel/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Form/ │ │ │ │ ├── BaseForm.tsx │ │ │ │ ├── BasePopoverForm.tsx │ │ │ │ ├── baseForm.less │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Header/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Icon/ │ │ │ │ ├── icon.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Image/ │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── List/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── LongText/ │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Notice/ │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Qrcode/ │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── RichText/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Tab/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Text/ │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── WhiteTpl/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── schema.ts │ │ │ └── template.ts │ │ ├── common.ts │ │ ├── media/ │ │ │ ├── Audio/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Calendar/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Map/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Video/ │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── schema.ts │ │ │ └── template.ts │ │ ├── schema.ts │ │ ├── shop/ │ │ │ ├── CardLabel/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Coupons/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── List/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── Tab/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── ZhuanLan/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── schema.ts │ │ │ │ └── template.ts │ │ │ ├── schema.ts │ │ │ └── template.ts │ │ └── visual/ │ │ ├── Area/ │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ ├── schema.ts │ │ │ └── template.ts │ │ ├── Chart/ │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ ├── schema.ts │ │ │ └── template.ts │ │ ├── Line/ │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ ├── schema.ts │ │ │ └── template.ts │ │ ├── Pie/ │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ ├── schema.ts │ │ │ └── template.ts │ │ ├── XProgress/ │ │ │ ├── index.tsx │ │ │ ├── schema.ts │ │ │ └── template.ts │ │ ├── schema.ts │ │ └── template.ts │ ├── pages/ │ │ ├── document.ejs │ │ ├── editor/ │ │ │ ├── Container.tsx │ │ │ ├── SourceBox.tsx │ │ │ ├── TargetBox.tsx │ │ │ ├── components/ │ │ │ │ ├── CanvasControl/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ └── Header/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── index.js │ │ │ ├── index.less │ │ │ ├── models/ │ │ │ │ ├── editorModal.js │ │ │ │ └── editorPcModel.ts │ │ │ ├── preview.tsx │ │ │ └── services/ │ │ │ └── editorService.js │ │ ├── help/ │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── home/ │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── ide/ │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── login/ │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── mobileTip.tsx │ │ └── user/ │ │ ├── base.less │ │ ├── index.less │ │ └── index.tsx │ ├── typings.d.ts │ ├── utils/ │ │ ├── req.ts │ │ └── tool.ts │ └── video-react.d.ts ├── tsconfig.json ├── webpack.config.js ├── website/ │ ├── css/ │ │ ├── frameworks.css │ │ └── style.css │ ├── index.html │ └── js/ │ ├── jquery.js │ ├── main.js │ └── plugins.js └── zh.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms # support simple dooring ! # weclome to try this repo. open_collective: h5-dooring ================================================ FILE: .github/ISSUE_TEMPLATE/custom.md ================================================ --- name: Custom issue template about: Describe this issue template's purpose here. title: '' labels: '' assignees: '' --- ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage *.lcov # nyc test coverage .nyc_output # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # TypeScript v1 declaration files typings/ # TypeScript cache *.tsbuildinfo # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Microbundle cache .rpt2_cache/ .rts2_cache_cjs/ .rts2_cache_es/ .rts2_cache_umd/ # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env .env.test # parcel-bundler cache (https://parceljs.org/) .cache # Next.js build output .next # Nuxt.js build / generate output .nuxt # Gatsby files .cache/ # Comment in the public line in if your project uses Gatsby and *not* Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public # vuepress build output .vuepress/dist # Serverless directories .serverless/ # FuseBox cache .fusebox/ # DynamoDB Local files .dynamodb/ # TernJS port file .tern-port .umi/ .umi-production/ # production /dist /doc-dist ================================================ FILE: .umirc.ts ================================================ import path from "path"; import { defineConfig } from "umi"; export default defineConfig({ dynamicImport: { loading: "@/components/LoadingCp" }, dva: { immer: true }, devtool: "source-map", antd: {}, title: "趣谈前端-h5-dooring", // exportStatic: {}, base: "/", publicPath: "/", outputPath: "dist", esbuild: {}, routes: [ { exact: false, path: "/", component: "@/layouts/index", routes: [ { path: "/", component: "../pages/home" }, { path: "/editor", component: "../pages/editor" }, { path: "/ide", component: "../pages/ide" }, { path: "/help", component: "../pages/help" }, { path: "/login", component: "../pages/login" }, { path: "/mobileTip", component: "../pages/mobileTip" }, { path: "/preview", component: "../pages/editor/preview" } ] } ], theme: { "primary-color": "#2F54EB" // "btn-primary-bg": "#2F54EB" }, extraBabelPlugins: [["import", { libraryName: "zarm", style: true }]], // sass: {}, alias: { components: path.resolve(__dirname, "src/components/"), utils: path.resolve(__dirname, "src/utils/"), assets: path.resolve(__dirname, "src/assets/") } }); ================================================ FILE: .vscode/settings.json ================================================ { "workbench.colorCustomizations": { "activityBar.background": "#152B60", "titleBar.activeBackground": "#1D3C86", "titleBar.activeForeground": "#FBFCFE" }, "editor.snippetSuggestions": "bottom", "editor.suggest.snippetsPreventQuickSuggestions": true } ================================================ FILE: CHANGELOG.md ================================================ ## 私有化授权版更新日志 [在线地址](http://h5.dooring.cn/h5_plus) #### 2.50 1. 复制页面添加数量校验 2. 后台系统模版列表添加“上推荐”按钮 3. 精选模版支持分类,分页 4. 编辑器页面我的页面支持分页, 继续编辑, 按钮放到标题右边 5. 优化前进后退组件配置项文案 6. 解决画布缩放导致的组件拖拽抖动 #### 2.40 1. 图片组件添加查看大图功能 2. 添加组件选中状态及样式优化 3. 添加功能类组件(统计组件) 4. 右键菜单体验优化 5. 删除服务端无用路由,降低内耗 #### 2.30 1. 优化用户注册机制 2. 组件动画添加延迟时间, 添加旋转动画, 优化动画逻辑 3. 优化用户登录态失效逻辑 4. 统计组件 5. 图片库弹窗层级优化 6. 服务器增加数据访问权限, 保障数据安全 #### 2.15 1. 编辑器支持调试模式(支持本地环境一键debug, 支持真机调试) 2. Tab组件支持布局(单列 / 双列) 3. header组件升级, 支持顶部固定, 自定义头部菜单 4. 添加1个行业模版 5. 优化登录逻辑, 自动去空格 6. 编辑器入口页面优化, 重构 7. 表单组件提交逻辑优化,修复参数错误提示 8. 支持自定义上传组件, 组件预览, 审批, 组件管理 #### 2.10 1. 添加入口页加群指引动画, 优化左侧界面 2. 优化拖拽更新算法, 使得拖拽精度达到99.99%, 真正的所搭即所得 3. 删除模版库无用模版, 创建2个新模版 4. 编辑器添加智能引导页面 5. 编辑器支持调试模式(支持本地环境一键debug, 支持真机调试) 6. Tab组件支持布局(单列 / 双列) #### 2.01 1. 优化编辑器加载性能 2. iframe容器组件添加边框等属性 3. 富文本组件添加背景色配置 4. 修复真机预览时空数据还能显示二维码bug 5. 优化页面高度适配问题, 添加高度适配器 6. 优化组件交互时空链接点击出现message bug 7. 更新dooring文档 #### 2.0 1. 完善数据源功能 2. 轮播图/图片列表/List/文字跑马灯/横向滚动组件数据源对接完毕 3. 组件库支持搜索功能 4. 组件列表支持分页, 提高渲染性能 5. 赞助墙交互优化 6. 界面局部优化 #### 1.99 1. 添加数据源功能 2. 视频组件支持封面图 3. 优化页面DSL结构, 降低了jsonSchema体积30%-50% 4. 官网优化 5. 管理后台替换logo, 部分文案信息 6. 添加图片列表组件 7. 轮播图支持一键绑定数据源 #### 1.98 1. 编辑器功能区添加更多折叠下拉框, 优化头部界面 2. 添加数据源入口和界面 3. 模版库优化, 剔除无用模版, 累计60+模版 4. 入口页添加赞助墙 5. 升级视频组件, 支持弹幕, 截屏, 模式设置等功能 6. 文件上传路径兼容window服务器本地化部署 #### 1.96 1. 修复首页推荐项目外链地址和站内文案 2. 替换Dooring网站logo 3. 优化ios8以下访问H5时可能出现的页面卡顿问题 4. 图片上传组件添加svg, gif图片格式支持 5. 后台管理系统添加一键跳编辑器按钮 6. 服务端编辑侧路由加固 7. 文件上传组件添加自定义上传文档,支持七牛云,腾讯云,阿里oss等第三方图床方式 #### 1.95 1. dooring文档添加更新日志模块 2. dooring增报错监控函数, 提供一键清空缓存按钮和自动重载功能 3. 新增电商商品H5模版 4. 页面配置增加背景模式和背景重复 5. 表单添加字段名配置项 #### 1.94 1. 转盘组件支持转盘交互功能(跳转链接/打开弹窗/自定义代码) 2. 添加网站拦截, 防止页面误关导致页面无法保存 3. 优化页面控制条组件样式 4. 按钮组件添加组件动画 5. 图片组件添加组件动画 6. 媒体组件icon优化 7. 全局错误监控组件添加一键清除缓存功能 #### 1.93 1. 上线源码下载功能 2. 服务端支持下载源码服务和下载次数限制 3. 界面部分文案优化 4. 出码基座优化 5. 抽奖组件支持抽奖后自定义交互(弹窗/链接/自定义代码) #### 1.92 1. 修复背景图预览适配问题 2. 转盘组件支持中奖后自定义交互/弹窗/自定义代码 3. 界面局部调整 4. 后台管理表单数据支持多键查询 5. 可视化大屏柱状图组件支持实时数据请求 ================================================ FILE: Dockerfile ================================================ FROM nginx:latest COPY ./default.conf /etc/nginx/conf.d/default.conf ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: SECURITY.md ================================================ # Security Policy ## Supported Versions Use this section to tell people about which versions of your project are currently being supported with security updates. | Version | Supported | | ------- | ------------------ | | 5.1.x | :white_check_mark: | | 5.0.x | :x: | | 4.0.x | :white_check_mark: | | < 4.0 | :x: | ## Reporting a Vulnerability Use this section to tell people how to report a vulnerability. Tell them where to go, how often they can expect to get an update on a reported vulnerability, what to expect if the vulnerability is accepted or declined, etc. ================================================ FILE: doc/.vuepress/config.js ================================================ module.exports = { base: "/doc/", title: "h5-dooring", dest: "./doc-dist", themeConfig: { search: false, searchMaxSuggestions: 10, lastUpdated: "Last Updated", nav: [ { text: "首页", link: "/" }, { text: "文档", link: "/zh/guide/" }, // { text: '1.X', link: '/zh/guide/' }, // { text: '语言', link: '/zh/guide/' }, { text: "体验", link: "http://h5.dooring.cn" }, { text: "github", link: "https://github.com/MrXujiang/h5-Dooring" } ], sidebar: [ { title: "基本介绍", path: "/zh/guide/", collapsable: false, sidebarDepth: 1 }, { title: "doring如何工作", path: "/zh/guide/introduced", collapsable: false, sidebarDepth: 1 }, { title: "快速上手", path: "/zh/guide/startedQuickly", collapsable: false, sidebarDepth: 1 }, { title: "目录结构", path: "/zh/guide/directoryStructure", collapsable: false, sidebarDepth: 1 }, { title: "组件开发", collapsable: false, sidebarDepth: 1, type: "group", children: [ { name: "componentStructure", title: "组件结构", path: "/zh/guide/componentDev/componentStructure", collapsable: false, sidebarDepth: 2 }, { name: "DSLAnalysis", title: "DSL设计", path: "/zh/guide/componentDev/DSLAnalysis", collapsable: false, sidebarDepth: 2 }, { name: "dynamicLoading", title: "动态加载", path: "/zh/guide/componentDev/dynamicLoading", collapsable: false, sidebarDepth: 1 } ] }, { title: "功能实现", collapsable: false, sidebarDepth: 1, type: "group", children: [ { title: "模板库", path: "/zh/guide/functionRealization/templateLibrary", collapsable: false, sidebarDepth: 1 }, { title: "保存json", path: "/zh/guide/functionRealization/saveJson", collapsable: false, sidebarDepth: 1 }, { title: "下载源码", path: "/zh/guide/functionRealization/download", collapsable: false, sidebarDepth: 1 }, { title: "网页预览", path: "/zh/guide/functionRealization/pagePreview", collapsable: false, sidebarDepth: 1 }, { title: "真机预览", path: "/zh/guide/functionRealization/machinePreview", collapsable: false, sidebarDepth: 1 }, { title: "撤销/重做", path: "/zh/guide/functionRealization/revocation", collapsable: false, sidebarDepth: 1 }, { title: "截图功能", path: "/zh/guide/functionRealization/screenshot", collapsable: false, sidebarDepth: 1 } ] }, { title: "私有化部署和二次开发", collapsable: false, sidebarDepth: 1, type: "group", children: [ { title: "私有化部署", path: "/zh/guide/deployDev/deploy", collapsable: false, sidebarDepth: 1 }, { title: "v6.dooring私有化部署(临时)", path: "/zh/guide/deployDev/deploy_v6", collapsable: false, sidebarDepth: 1 }, { title: "服务端数据说明", path: "/zh/guide/deployDev/dir", collapsable: false, sidebarDepth: 1 }, { title: "支持https", path: "/zh/guide/deployDev/https", collapsable: false, sidebarDepth: 1 }, { title: "接入第三方oss", path: "/zh/guide/deployDev/oss", collapsable: false, sidebarDepth: 1 }, { title: "获取Form组件的值数据", path: "/zh/guide/deployDev/form", collapsable: false, sidebarDepth: 1 }, { title: "API接口文档", path: "/zh/guide/deployDev/api", collapsable: false, sidebarDepth: 1 }, { title: "更新日志", path: "/zh/guide/deployDev/log", collapsable: false, sidebarDepth: 1 } ] } ] } }; ================================================ FILE: doc/.vuepress/templates/dev.html ================================================ dooring-前端开发手册
================================================ FILE: doc/.vuepress/theme/enhanceApp.js ================================================ import "./styles/main.scss"; // 使用异步函数也是可以的 export default ({ Vue, // VuePress 正在使用的 Vue 构造函数 options, // 附加到根实例的一些选项 router, // 当前应用的路由实例 siteData, // 站点元数据 isServer // 当前应用配置是处于 服务端渲染 或 客户端 }) => { // ...做一些其他的应用级别的优化 // console.log({ Vue, options, router, siteData, isServer }); Vue.config.ignoredElements = [ // Use a `RegExp` to ignore all elements that start with "nova-" // 2.5+ only //^nova-/, // /img/, ]; }; ================================================ FILE: doc/.vuepress/theme/global-components/Home.vue ================================================ ================================================ FILE: doc/.vuepress/theme/index.js ================================================ module.exports = { extend: "@vuepress/theme-default" }; ================================================ FILE: doc/.vuepress/theme/layouts/Layout.vue ================================================ ================================================ FILE: doc/.vuepress/theme/styles/_layout.scss ================================================ $accentColor: #083ac4; .nav-link.external { .outbound { display: none; } } .nav-link.external:last-child { color: #fff; background-color: $accentColor; border-color: $accentColor; padding: 6px 14px; border-radius: 4px; } .doc-main { padding-top: 88px; padding-left: 380px; } ================================================ FILE: doc/.vuepress/theme/styles/_reset.scss ================================================ /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ /* Document ========================================================================== */ /** * 1. Correct the line height in all browsers. * 2. Prevent adjustments of font size after orientation changes in * IE on Windows Phone and in iOS. */ // * { // box-sizing: border-box; // margin: 0; // padding: 0; // } html { line-height: 1.15; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ } /* Sections ========================================================================== */ /** * Remove the margin in all browsers (opinionated). */ body { margin: 0; padding: 0; } /** * Add the correct display in IE 9-. */ article, aside, footer, header, nav, section { display: block; } /** * Correct the font size and margin on `h1` elements within `section` and * `article` contexts in Chrome, Firefox, and Safari. */ h1, h2, h3, h4, h5 { margin: 0; padding: 0; } /** * Correct the font size and margin on `p` elements */ /* Grouping content ========================================================================== */ /** * Add the correct display in IE 9-. * 1. Add the correct display in IE. */ figcaption, figure, main { /* 1 */ display: block; } /** * Add the correct margin in IE 8. */ figure { margin: 0; padding: 0; } /** * 1. Add the correct box sizing in Firefox. * 2. Show the overflow in Edge and IE. */ hr { box-sizing: content-box; /* 1 */ height: 0; /* 1 */ overflow: visible; /* 2 */ } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ pre { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /* Text-level semantics ========================================================================== */ /** * 1. Remove the gray background on active links in IE 10. * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. */ a { background-color: transparent; /* 1 */ -webkit-text-decoration-skip: objects; /* 2 */ color: #329aff; } /** * 1. Remove the bottom border in Chrome 57- and Firefox 39-. * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. */ abbr[title] { border-bottom: none; /* 1 */ text-decoration: underline; /* 2 */ text-decoration: underline dotted; /* 2 */ } /** * Prevent the duplicate application of `bolder` by the next rule in Safari 6. */ b, strong { font-weight: inherit; } /** * Add the correct font weight in Chrome, Edge, and Safari. */ b, strong { font-weight: bolder; } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ code, kbd, samp { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /** * Add the correct font style in Android 4.3-. */ dfn { font-style: italic; } /** * Add the correct background and color in IE 9-. */ mark { background-color: #ff0; color: #000; } /** * Add the correct font size in all browsers. */ small { font-size: 80%; } /** * Prevent `sub` and `sup` elements from affecting the line height in * all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.5em; } /* Embedded content ========================================================================== */ /** * Add the correct display in IE 9-. */ audio, video { display: inline-block; } /** * Add the correct display in iOS 4-7. */ audio:not([controls]) { display: none; height: 0; } /** * Remove the border on images inside links in IE 10-. */ img { border-style: none; } /** * Hide the overflow in IE. */ svg:not(:root) { overflow: hidden; } /* Forms ========================================================================== */ /** * 1. Change the font styles in all browsers (opinionated). * 2. Remove the margin in Firefox and Safari. */ button, input, optgroup, select, textarea { font-family: sans-serif; /* 1 */ font-size: 100%; /* 1 */ line-height: 1.15; /* 1 */ margin: 0; /* 2 */ padding: 0; } /** * Show the overflow in IE. * 1. Show the overflow in Edge. */ button, input { /* 1 */ overflow: visible; outline: none; } /** * Remove the inheritance of text transform in Edge, Firefox, and IE. * 1. Remove the inheritance of text transform in Firefox. */ button, select { /* 1 */ text-transform: none; } /** * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` * controls in Android 4. * 2. Correct the inability to style clickable types in iOS and Safari. */ button, html [type="button"], /* 1 */ [type="reset"], [type="submit"] { -webkit-appearance: button; /* 2 */ } /** * Remove the inner border and padding in Firefox. */ button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; } /** * Restore the focus styles unset by the previous rule. */ button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; } /** * Correct the padding in Firefox. */ fieldset { padding: 0.35em 0.75em 0.625em; } /** * 1. Correct the text wrapping in Edge and IE. * 2. Correct the color inheritance from `fieldset` elements in IE. * 3. Remove the padding so developers are not caught out when they zero out * `fieldset` elements in all browsers. */ legend { box-sizing: border-box; /* 1 */ color: inherit; /* 2 */ display: table; /* 1 */ max-width: 100%; /* 1 */ padding: 0; /* 3 */ white-space: normal; /* 1 */ } /** * 1. Add the correct display in IE 9-. * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. */ progress { display: inline-block; /* 1 */ vertical-align: baseline; /* 2 */ } /** * Remove the default vertical scrollbar in IE. */ textarea { overflow: auto; } /** * 1. Add the correct box sizing in IE 10-. * 2. Remove the padding in IE 10-. */ [type="checkbox"], [type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** * Correct the cursor style of increment and decrement buttons in Chrome. */ [type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; } /** * 1. Correct the odd appearance in Chrome and Safari. * 2. Correct the outline style in Safari. */ [type="search"] { -webkit-appearance: textfield; /* 1 */ outline-offset: -2px; /* 2 */ } /** * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. */ [type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** * 1. Correct the inability to style clickable types in iOS and Safari. * 2. Change font properties to `inherit` in Safari. */ ::-webkit-file-upload-button { -webkit-appearance: button; /* 1 */ font: inherit; /* 2 */ } /* Interactive ========================================================================== */ /* * Add the correct display in IE 9-. * 1. Add the correct display in Edge, IE, and Firefox. */ details, /* 1 */ menu { display: block; } /* * Add the correct display in all browsers. */ summary { display: list-item; } /* Scripting ========================================================================== */ /** * Add the correct display in IE 9-. */ canvas { display: inline-block; } /** * Add the correct display in IE. */ template { display: none; } /* Hidden ========================================================================== */ /** * Add the correct display in IE 10-. */ [hidden] { display: none; } input { outline: none; } /*reset browser scroll style*/ html, body { scrollbar-arrow-color: rgba(209, 213, 219, 1); /**/ /*三角箭头的颜色*/ scrollbar-face-color: rgba(209, 213, 219, 1); /**/ /*立体滚动条的颜色*/ scrollbar-3dlight-color: rgba(209, 213, 219, 1); /**/ /*立体滚动条亮边的颜色*/ scrollbar-highlight-color: rgba(209, 213, 219, 1); /**/ /*滚动条空白部分的颜色*/ scrollbar-shadow-color: rgba(209, 213, 219, 1); /**/ /*立体滚动条阴影的颜色*/ scrollbar-darkshadow-color: rgba(209, 213, 219, 1); /**/ /*立体滚动条强阴影的颜色*/ scrollbar-track-color: rgba(209, 213, 219, 1); /**/ /*立体滚动条背景颜色*/ scrollbar-base-color: rgba(244, 245, 249, 1); /**/ /*滚动条的基本颜色*/ } /* chrome scroll style */ /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/ ::-webkit-scrollbar { width: 6px; height: 6px; background-color: transparent; } /*定义滚动条轨道 内阴影+圆角*/ ::-webkit-scrollbar-track { background-color: transparent; } /*定义滑块*/ ::-webkit-scrollbar-thumb { border-radius: 4px; background-color: rgba(209, 213, 219, 1); } ul li { // list-style: none; padding: 0; margin: 0; } dl, dt, dd { margin: 0; padding: 0; } button { cursor: pointer; border: none; } button[disabled] { cursor: not-allowed; } ================================================ FILE: doc/.vuepress/theme/styles/main.scss ================================================ @import 'reset'; @import 'layout'; ================================================ FILE: doc/.vuepress/theme/styles/palette.styl ================================================ $accentColor= #083ac4; ================================================ FILE: doc/README.md ================================================ --- content: Home home: true #heroImage: ../imgs/common/logo.svg heroText: 一款所见即所得的H5编辑器 features: - title: 简洁方便 details: 任何人只需傻瓜式拖拽或进行简单编辑即可生成精美的H5页面 - title: 插拔式体验 details: 产品以GPL协议开源, 授权后可植入任何系统,并支持二次开发 - title: 持续迭代,无限可能 details: 目前正在持续迭代中,后续可根据需求开发功能更强大的可视化系统 actionText: 快速上手 → actionLink: /zh/guide/ footer: GPL Licensed | Copyright © 2020-present H5-Dooring --- ================================================ FILE: doc/zh/guide/README.md ================================================ foo H5-Dooring 是一款功能强大,高可扩展的 H5 可视化页面配置解决方案,致力于提供一套简单方便、专业可靠、无限可能的 H5 落地页最佳实践。 ## 功能特点 🎉 **可扩展,** Dooring 实现了较为完整的业务闭环,并使其模块化,编辑器内部功能接口也全部可以对接不同服务端语言,实现了标准化接口。此外还支持自定义组件,二次开发,设计模板等能力,以满足功能和跨领域的分层需求。 📦 **开箱即用,** Dooring 内置了**表单渲染器、页面渲染器、动态加载内核**等,仅需一套源码即可上手开发。并且还提供针对 React 的定制插件,内涵丰富的功能,可满足日常 80%的页面制作需求。 🚀 **大量自研,** 包含整个编辑器架构、组件设计、文档、请求库封装,后台管理系统等,满足日常项目的周边需求。 🚄 **与时俱进,** 在满足需求的同时,我们也不会停止对新技术的探索。比如更多**营销组件、业务功能,后台管理可视化,PC 页面编辑器,数据大屏定制**等等。 ## 为什么选择 Dooring 目前**github**已超过 3000+star,上线 2 个月累计 500+用户使用,解决完善了 100+问题,后续会持续迭代,更新,自研优秀,先进的 lowcode/nocode 解决方案。 ================================================ FILE: doc/zh/guide/building.md ================================================ 正在建设中... ================================================ FILE: doc/zh/guide/componentDev/DSLAnalysis.md ================================================ # DSL 设计 DSL 层主要约定了 Dooring 组件的数据协议,包括组件的可编辑属性、编辑类型、初始值等,之所以定义一致的协议层,主要是方便后期的组件扩展,配置后移,有助于不同后端语言开发和数据存储,接下来我们看看 header 组件的 schema。 1.editData 可编辑的属性类型 DSL 2.config 可编辑组件的默认属性 ```js const Header: IHeaderSchema = { editData: [ { key: "bgColor", name: "背景色", type: "Color" }, { key: "height", name: "高度", type: "Number" }, { key: "logo", name: "logo", type: "Upload", isCrop: true, cropRate: 1000 / 618 }, { key: "logoText", name: "logo文字", type: "Text" }, { key: "color", name: "文字颜色", type: "Color" }, { key: "fontSize", name: "文字大小", type: "Number" } ], config: { bgColor: "rgba(245,245,245,1)", logo: [ { uid: "001", name: "image.png", status: "done", url: `${serverUrl}/uploads/3_1740be8a482.png` } ], logoText: "页头Header", fontSize: 20, color: "rgba(47,84,235,1)", height: 50 } }; ``` 由以上代码可知,我们可以在 editData 属性中给组件添加可编辑的属性,比如背景图,然后再 component 中接受属性从而设置样式。 在 config 属性中,我们可以设置组件默认属性值,和 editData 中每一项的 key 一一对应。 ================================================ FILE: doc/zh/guide/componentDev/componentStructure.md ================================================ # 组件结构 dooring 的组件设计包含以下 3 个部分组件: 1、component 组件主体 2、schema 组件的 DSL,结构协议层 3、template 定义了组件的类型、外观、从属关系,后期考虑纳入 schema 接下来我会介绍一个基本的组件主体设计,以为 template 设计,在下一章会具体介绍 schema 部分。 ## 组件设计 我们这里拿基本的 header 组件来举例,如下是 header 组件的代码: ```jsx interface HeaderPropTypes extends IHeaderConfig { isTpl: boolean; } const Header = memo((props: HeaderPropTypes) => { const { bgColor, logo, logoText, fontSize, color } = props; return props.isTpl ? (
) : (
{logoText}
{logoText}
); }); ``` 我们只需要按照上面的方式编写组件即可,props 是 DSL 定义的数据层,用来控制组件的 shape,也就是组件的表现。我们看看 header 对应的 template。 ## template 设计 ```js const template = { type: "Header", h: 28, displayName: "页头组件" }; export default template; ``` 以上就是我们 template 的结构,type 用来定义组件的类型,方便渲染器动态查找,h 代表组件的初始化高度,我们可以自由设置。displayName 是组件的中文名,用来在左侧组件面板中展示,方便用户理解,我们可以在 template 中自定义更多辅助信息,方便使用者更高效的使用我们的编辑器。 ## schema 设计 开发一个自定义组件需要包含 3 部分, `Component`, `Schema` 和 `Template`. 接下来我们看一下 `Header` 组件的 `Schema`. ```js import { IColorConfigType, INumberConfigType, ITextConfigType, IUploadConfigType, TColorDefaultType, TNumberDefaultType, TTextDefaultType, TUploadDefaultType } from "@/components/FormComponents/types"; import { baseConfig, baseDefault, ICommonBaseType } from "../../common"; export type THeaderEditData = Array< IColorConfigType | INumberConfigType | IUploadConfigType | ITextConfigType >; export interface IHeaderConfig extends ICommonBaseType { bgColor: TColorDefaultType; logo: TUploadDefaultType; logoText: TTextDefaultType; fontSize: TNumberDefaultType; color: TColorDefaultType; height: TNumberDefaultType; } export interface IHeaderSchema { editData: THeaderEditData; config: IHeaderConfig; } const Header: IHeaderSchema = { editData: [ ...baseConfig, { key: "bgColor", name: "背景色", type: "Color" }, { key: "height", name: "高度", type: "Number" }, { key: "logo", name: "logo", type: "Upload", isCrop: true, cropRate: 1000 / 618 }, { key: "logoText", name: "logo文字", type: "Text" }, { key: "color", name: "文字颜色", type: "Color" }, { key: "fontSize", name: "文字大小", type: "Number" } ], config: { bgColor: "rgba(0,0,0,1)", logo: [ { uid: "001", name: "image.png", status: "done", url: "http://49.234.61.19/uploads/3_1740be8a482.png" } ], logoText: "页头Header", fontSize: 20, color: "rgba(255,255,255,1)", height: 50, ...baseDefault } }; export default Header; ``` `editData`表示组件的可编辑属性, 我们可以自定义哪些组件可编辑. `config`为组件接收的属性, 和`editData`数组项中的`key`一一对应. ### 组件编辑区属性类型 `Dooring`组件编辑面板有如下对应编辑类型: - Upload 上传组件 - Text 文本框 - RichText 富文本 - TextArea 多行文本 - Number 数字输入框 - DataList 列表编辑器 - FileList 文件列表编辑器 - InteractionData 交互设置 - Color 颜色面板 - MutiText 多文本 - Select 选择下拉框 - Radio 单选框 - Switch 开关切换 - CardPicker 卡片面板 - Table 表格编辑器 - Pos 坐标编辑器 - FormItems 表单设计器 ================================================ FILE: doc/zh/guide/componentDev/dynamicLoading.md ================================================ # 组件动态加载 目前 H5-Dooring 的组件都是通过动态加载的方式引入,好处是我们在页面中只会加载我们需要的组件,不需要的组件不会被加载,这样可以提高页面加载的速度,这样做也会出现一些问题,比如一个长页面,配置了很多组件,那么一个页面加载过程可以会触发多次请求,目前还没有遇到性能问题,但后续会逐渐优化这个问题。 ## umi3 提供的 dynamic 目前组件的动态加载我们采用的 umi 的 dynamic 方案,基于它我们上层封装了一个组件动态加载器,原理如下: foo 具体代码可以参考 Dooring 的 Github 地址:[https://github.com/MrXujiang/h5-Dooring](https://github.com/MrXujiang/h5-Dooring) ================================================ FILE: doc/zh/guide/deployDev/api.md ================================================ **H5-Dooring**后端部分主要使用 `Nodejs` 开发, 为了满足更多定制化需求和服务的可移植性, 特意编写了 API 接口文档, 方便大家使用不同的后端语言实现服务接入. - 注意: 接口统一前缀为`/api/v0` ## 用户相关 ### 用户登录 用户登录接口 - `POST` /vip/check | 参数名 | 是否必选 | 类型 | 说明 | | ------ | :------: | :----: | -----: | | n | true | string | 用户名 | | co | true | string | 密码 | 返回示例 ```json { "result": { "n": "test", "od": [], "h5": [ { "t": "23242ED", "n": "测试页面" } ], "rp": "AAAAA", "maxage": 300000 } } ``` ### 注销登录 注销接口 - `POST` /vip/checkout 返回示例 ```json { "result": null, "msg": "退出成功" } ``` ### 权限控制 不同用户级别所访问的页面权限不同, 这块可结合服务端已有代码设计属于自己的权限字段, 地址为`server/src/router` ### 用户列表 获取用户列表接口 - `GET` /vip/all 获取用户列表需要账号满足以下条件: - 已登录 - 为超级管理员 返回示例 ```json [ { "id": "", "n": "test", "co": "123456", "od": [], "h5": [ { "t": "23242ED", "n": "测试页面" } ], "wx": "Mr_xuxiaoxi", "rp": "AAAAA" } ] ``` ### 添加用户 添加用户接口 - `POST` /vip/add 先决条件: - 用户已登陆 - 为超级管理员 | 参数名 | 是否必选 | 类型 | 说明 | | -------- | :------: | :----: | -----: | | nickname | true | string | 用户名 | | wx | true | string | 微信号 | | co | true | string | 密码 | 注: co 是由笔者写的`加密算法`实现, 不需要手动填写, 详情见`dooirng`后台管理/用户管理页面. 返回示例 ```json { "id": "3422EF", "n": "test", "wx": "Mr_xuxiaoxi", "co": "123456", "od": [], "h5": [], "tpl": [], "rp": "AAAAA", "h5Num": 10, "tplNum": 3 } ``` ### 生成登录码 生成登录码接口 - `GET` /vip/gcode 先决条件: - 用户已登陆 - 为超级管理员 注: 生成登录码是由笔者写的`加密算法`实现, 不需要手动实现, 如果有自定义需求, 可以自行二次开发实现. 返回示例 ```json { "co": "1x2fgggteee3456_zdd4" } ``` `说明:` 为了保护用户信息安全, 返回的登录码是加密后的密文, 会调用笔者写的`xib.xip`方法进行加密, 如果想看到原始密码, 需要调用`xib.uxip`进行解密. ### 获取用户真实密码 获取用户真实密码接口 - `GET` /vip/gcode/get 先决条件: - 用户已登陆 - 为超级管理员 | 参数名 | 是否必选 | 类型 | 说明 | | ------ | :------: | :----: | -----------: | | co | true | string | 加密后的密码 | 返回示例 ```json { "co": "12345678" } ``` ### 修改用户信息 修改用户接口 - `POST` /vip/edit 先决条件: - 用户已登陆 - 为超级管理员 | 参数名 | 是否必选 | 类型 | 说明 | | -------- | :------: | :----: | ------: | | id | false | string | 用户 ID | | nickname | false | string | 用户名 | | co | false | string | 登录码 | | wx | false | string | 微信号 | 返回示例 ```json { "state": 200, "result": null, "msg": "修改成功" } ``` ### 删除用户 删除用户接口 - `DELETE` /vip/del 先决条件: - 用户已登陆 - 为超级管理员 | 参数名 | 是否必选 | 类型 | 说明 | | ------ | :------: | :----: | ------: | | id | true | string | 用户 ID | | wx | true | string | 微信号 | | n | true | string | 用户名 | 返回示例 ```json { "state": 200, "result": null, "msg": "删除成功" } ``` ## H5 页面管理 ### 获取 H5 数据 - `GET` /visible/h5/get 先决条件: - 用户已登陆 | 参数名 | 是否必选 | 类型 | 说明 | | ------ | :------: | :----: | ---------: | | tid | true | string | H5 唯一 id | 返回示例 ```json { "pageConfig": {}, "tpl": [ { "id": "879742", "item": { "type": "Carousel", "config": { "direction": "left", "swipeable": false, "autoPlay": false, "imgList": [ { "id": "1", "title": "趣谈小课1", "desc": "致力于打造优质小课程", "link": "xxxxx", "imgUrl": [ { "uid": "001", "name": "image.png", "status": "done", "url": "http://io.nainor.com/uploads/1_1740bd7c3dc.png" } ] }, { "id": "2", "title": "趣谈小课1", "desc": "致力于打造优质小课程", "link": "xxxxx", "imgUrl": [ { "uid": "001", "name": "image.png", "status": "done", "url": "http://io.nainor.com/uploads/2_1740bd8d525.png" } ] } ], "tplImg": "http://io.nainor.com/uploads/carousal_17442e1420f.png" }, "h": 82, "editableEl": [ { "key": "direction", "name": "方向", "type": "Radio", "range": [ { "key": "down", "text": "从上到下" }, { "key": "left", "text": "从左到右" } ] }, { "key": "swipeable", "name": "是否可拖拽", "type": "Switch" }, { "key": "autoPlay", "name": "是否自动播放", "type": "Switch" }, { "key": "imgList", "name": "图片列表", "type": "DataList" } ], "category": "base" }, "point": { "i": "x-0", "x": 0, "y": 13, "w": 24, "h": 82, "isBounded": true }, "status": "inToCanvas" }, { "id": "481194", "item": { "type": "Form", "config": { "title": "表单定制组件", "fontSize": 18, "titColor": "rgba(60,60,60,1)", "titWeight": "400", "bgColor": "rgba(255,255,255,1)", "btnColor": "rgba(20,54,226,100)", "btnTextColor": "rgba(255,255,255,1)", "api": "", "formControls": [ { "id": "1", "type": "Text", "label": "姓名", "placeholder": "请输入姓名" }, { "id": "2", "type": "Number", "label": "年龄", "placeholder": " 请输入年龄" }, { "id": "4", "type": "MySelect", "label": "爱好", "options": [ { "label": "选项一", "value": "1" }, { "label": "选项二", "value": "2" }, { "label": "选项三", "value": "3" } ] } ] }, "h": 172, "category": "base" }, "point": { "i": "x-1", "x": 0, "y": 98, "w": 24, "h": 172, "isBounded": true }, "status": "inToCanvas" } ] } ``` ### 保存 H5 数据 - `POST` /visible/h5/save 先决条件: - 用户已登陆 | 参数名 | 是否必选 | 类型 | 说明 | | ---------- | :------: | :----: | ------------------: | | pageConfig | false | object | H5 页面配置数据 | | tpl | true | object | H5 页面组件配置数据 | | tid | true | string | H5 页面唯一 id | 参数示例 ```json { "pageConfig": { "bgColor": "rgba(151,25,25,1)", "title": "医院宣传页" }, "tpl": [], "tid": "EF123D3" } ``` 返回示例 ```json { "state": 200, "result": { "tid": "EF123D3" }, "msg": "保存成功" } ``` ### 删除 H5 数据 - `DELETE` /visible/h5/del 先决条件: - 用户已登陆 | 参数名 | 是否必选 | 类型 | 说明 | | ------ | :------: | :----: | -------------: | | tid | true | string | H5 页面唯一 id | 返回示例 ```json { "state": 200, "result": [ { "tid": "EF123D3", "name": "test页面" }, { "tid": "EF123D6", "name": "test2页面" } ], "msg": "删除成功" } ``` ## H5 表单数据管理 ### 保存表单数据 - `POST` /vip/h5/form/post | 参数名 | 是否必选 | 类型 | 说明 | | -------------- | :------: | :----: | --------------: | | tid(query) | true | string | H5 页面唯一 id | | formData(body) | true | array | H5 页面表单数据 | 返回示例 ```json { "state": 200, "result": null, "msg": "表单提交成功" } ``` ### 批量导入表单数据 - `POST` /vip/h5/form/import | 参数名 | 是否必选 | 类型 | 说明 | | -------------- | :------: | :----: | ------------------: | | tid(query) | true | string | H5 页面唯一 id | | formData(body) | true | array | H5 页面表单数据集合 | 返回示例 ```json { "state": 200, "result": null, "msg": "批量导入成功" } ``` ### 删除表单数据 - `DELETE` /vip/h5/form/del | 参数名 | 是否必选 | 类型 | 说明 | | ------ | :------: | :----: | -------------: | | tid | true | string | H5 页面唯一 id | | ID | true | string | 表单专属 id | 返回示例 ```json { "state": 200, "result": null, "msg": "删除成功" } ``` ## 模版管理 ### 获取模版库 - `GET` /visible/tpls/free 返回示例 ```json { "state": 200, "result": [ { "img": "http://xxx/uploads/tpl_175adabd8dd.jpg", "name": "合作模版", "tid": "B73349B6" } ] } ``` ### 保存模版 - `POST` /visible/tpl/save 先决条件: - 用户已登陆 | 参数名 | 是否必选 | 类型 | 说明 | | ---------- | :------: | :----: | --------------: | | name | true | string | H5 模版名称 | | cate | true | string | H5 模版分类 | | img | false | string | H5 模版封面图 | | tpl | true | array | H5 模版数据 | | pageConfig | false | object | H5 模版全局配置 | 返回示例 ```json { "state": 200, "result": { "tid": "B73349B6" }, "msg": "保存成功" } ``` ### 删除模版 - `DELETE` /visible/tpl/del 先决条件: - 用户已登陆 | 参数名 | 是否必选 | 类型 | 说明 | | ------ | :------: | :----: | ---------: | | tid | true | string | H5 模版 id | 返回示例 ```json { "state": 200, "result": null, "msg": "删除成功" } ``` ## 文件上传 ## 数据统计 ### 数据大盘接口 ### 页面埋点 ================================================ FILE: doc/zh/guide/deployDev/deploy.md ================================================ 私有化部署需要获取 4 个核心项目包, 包括 - H5 编辑器(h5_plus) - H5 基座(h5) - Dooring 管理后台(Dooring-Admin) - 服务端项目(Server) 获取以上四个核心源码工程需要满足商业授权协议, 具体可联系作者[徐小夕](http://h5.dooring.cn/uploads/WechatIMG3_1758e9753e2.jpeg) ### 部署架构图 H5-dooring部署 部署流程如下: 1. 下载 4 个源码工程, 安装依赖(npm install 或 yarn) 2. 打包 3 个前端工程至`server`的 static 目录下 3. 在`server`下本地运行 `yarn start` 或 `npm start` 启动服务端进行本地测试 4. 打包服务端代码, `yarn build` 生成 `dist` 目录, 建议使用 `pm2` 做`nodejs`服务的负载均衡, 运行 `pm2 start dist/index.js`启动生产环境代码 也可以将以上步骤集成到 gitlab 等 CI, CD 服务中, 进行自动化打包发布, 或者采用`docker`进行容器化部署. ### 步骤 3.4 详细流程 #### 1. 安装项目环境 服务器需提前安装 node 和 pm2, 将本项目上传至服务器指定的目录(如/www/activity), 进入项目目录, 执行: ``` npm install ``` #### 2. 修改项目域名 进入`./src/config/index.js`, 修改`staticPath`变量为当前服务器域名/ip, 如`http://xxx.com`或`http://xxx.com:8080`(如非 80 端口) #### 3. 编译项目 执行`npm run build`编译项目, 生成`dist`目录 #### 4. 运行项目 在项目根目录执行 `pm2 start dist/index.js`启动项目 ================================================ FILE: doc/zh/guide/deployDev/deploy_v6.md ================================================ 私有化部署需要获取 3 个核心项目包, 包括 - 可视化大屏编辑器(v6.dooring/) - v6 管理后台(v6.dooring/manage) - 服务端项目(v6.dooring/server) 获取以上三个核心源码工程需要满足商业授权协议, 具体可参考[商业授权方案](http://h5.dooring.cn/h5_plus/price) ### 部署架构图 H5-dooring部署 部署流程如下: 1. 下载 3 个源码工程, 安装依赖(npm install 或 yarn) 2. 打包 2 个前端工程至`server`的 static 目录下 3. 在`server`下本地运行 `yarn start` 或 `npm start` 启动服务端进行本地测试 4. 打包服务端代码, `yarn build` 生成 `dist` 目录, 建议使用 `pm2` 做`nodejs`服务的负载均衡, 运行 `pm2 start dist/index.js`启动生产环境代码 也可以将以上步骤集成到 gitlab 等 CI, CD 服务中, 进行自动化打包发布, 或者采用`docker`进行容器化部署. ### 步骤 3.4 详细流程 #### 1. 安装项目环境 服务器需提前安装 node 和 pm2, 将本项目上传至服务器指定的目录(如/www/activity), 进入项目目录, 执行: ``` npm install ``` #### 2. 修改项目域名 进入`./src/config/index.js`, 修改`staticPath`变量为当前服务器域名/ip, 如`http://xxx.com`或`http://xxx.com:8080`(如非 80 端口) #### 3. 编译项目 执行`npm run build`编译项目, 生成`dist`目录 #### 4. 运行项目 在项目根目录执行 `pm2 start dist/index.js`启动项目 ================================================ FILE: doc/zh/guide/deployDev/dir.md ================================================ 服务端主要是我们的`server`工程, 数据主要存放在`server/public`下, 具体数据指代含义我们接下来会详细介绍. - bed 存放图片库中的分类图片, 私有化部署的用户可以直接在此处扩充图片(更好的建议是直接存到第三方图床) - h5 用户保存的 h5 数据文件, 一个页面对应一个 json 文件 - h5_tpl 平台保存的模版数据文件夹 - xxx.json 模版页面文件 - tpls.json 模版库中的模版列表数据, 可以手动清空 - h5_vip 会员数据目录 - form 会员制作的含表单页面的表单收集数据 - view.json 用户浏览量数据 - vip.json 会员列表数据 - vipCard.json 会员订单数据(暂时无用, 可删除) - image.json 图片库, 主要用来渲染页面的图片库数据 - city.json 省市 3 级联动数据, 为表单组件提供数据支持 ================================================ FILE: doc/zh/guide/deployDev/form.md ================================================ ### 获取 Form 组件的值数据 Form 表单组件在`editor`目录下`src/components/BasicShop/BasicComponents`位置. Form 组件是`Dooring`的核心组件之一, 内部的值通过 Form 组件内部收集, 当然我们也可以暴露出来让其他交互或者组件消费(需要一定的二次开发), 关键代码如下: ```js req .post(`/vip/h5/form/post${location.search}`, { ...fields, ...formData }) .then(res => { if (type === "link") { // 解析参数 let isPre = content.indexOf("?") < 0; let query = { dr: Date.now(), from: urlParmas.tid }; try { query = params ? { ...JSON.parse(params), ...query } : query; } catch (err) { console.log(err); } // 跳转 if (content.indexOf("http") > -1) { window.location.href = content + urlencode(query, isPre); return; } history.push(`/m?tid=${content}&${urlencode(query)}`); } else if (type === "modal") { setVisible(true); } else if (type === "code") { eval(content); } }); ``` 数据收集提交的核心代码在 Form 组件的第 56-149 行, 也就是`submit`方法. 表单组件收集到的数据统一存放在代码中的`formData`字段, 所以要想在其他地方获取用户表单填写的值, 我们只需要手动将`formData`传递出去, 或者挂载到全局(如 window 对象, localStorage, indexedDB 等). ================================================ FILE: doc/zh/guide/deployDev/https.md ================================================ 目前**H5-Dooring**全面支持 https 部署, 具体方式方案如下. ### 前端工程 我们需要在前端工程中的`src/pages/document.ejs`中的`head`中添加如下代码: ```html ``` 目的是强制将页面中 HTTP 请求转换为 HTTPS. ### 服务器工程 #### 1. 申请 SSL 证书 #### 2. 生成 server.csr+server.key #### 3. 通过证书链生成.pem 文件 #### 在`server`中的`src/index.js`按如下方式修改 ```js // 忽略部分无影响代码 import https from "https"; // 你的ssl存放路径, 建议直接放在server目录下 const filePath = path.join(__dirname, "../ssl"); // 启动逻辑 async function start() { // https配置 const httpsOptions = { key: fs.readFileSync(path.join(filePath, "3536084__doctopia.com.cn.key")), //ssl文件路径 cert: fs.readFileSync(path.join(filePath, "3536084__doctopia.com.cn.pem")) //ssl文件路径 }; // https服务 const server = https.createServer(httpsOptions, app.callback()); const io = require("socket.io")(server); // 忽略其他无影响代码 // https默认443, 这里我们可以走公共配置 server.listen(443, () => { console.log(`服务器地址:${config.staticPath}`); }); } start(); ``` ================================================ FILE: doc/zh/guide/deployDev/log.md ================================================ ### 更新日志 #### 1.99 1. 添加数据源功能 2. 视频组件支持封面图 3. 优化页面 DSL 结构, 降低了 jsonSchema 体积 30%-50% 4. 官网优化 5. 管理后台替换 logo, 部分文案信息 6. 添加图片列表组件 7. 轮播图支持一键绑定数据源 #### 1.98 1. 编辑器功能区添加更多折叠下拉框, 优化头部界面 2. 添加数据源入口和界面 3. 模版库优化, 剔除无用模版, 累计 60+模版 4. 入口页添加赞助墙 5. 升级视频组件, 支持弹幕, 截屏, 模式设置等功能 6. 文件上传路径兼容 window 服务器本地化部署 #### 1.96 1. 修复首页推荐项目外链地址和站内文案 2. 替换 Dooring 网站 logo 3. 优化 ios8 以下访问 H5 时可能出现的页面卡顿问题 4. 图片上传组件添加 svg, gif 图片格式支持 5. 后台管理系统添加一键跳编辑器按钮 6. 服务端编辑侧路由加固 7. 文件上传组件添加自定义上传文档,支持七牛云,腾讯云,阿里 oss 等第三方图床方式 #### 1.95 1. dooring 文档添加更新日志模块 2. dooring 增报错监控函数, 提供一键清空缓存按钮和自动重载功能 3. 新增电商商品 H5 模版 4. 页面配置增加背景模式和背景重复 5. 表单添加字段名配置项 #### 1.94 1. 转盘组件支持转盘交互功能(跳转链接/打开弹窗/自定义代码) 2. 添加网站拦截, 防止页面误关导致页面无法保存 3. 优化页面控制条组件样式 4. 按钮组件添加组件动画 5. 图片组件添加组件动画 6. 媒体组件 icon 优化 7. 全局错误监控组件添加一键清除缓存功能 #### 1.93 1. 上线源码下载功能 2. 服务端支持下载源码服务和下载次数限制 3. 界面部分文案优化 4. 出码基座优化 5. 抽奖组件支持抽奖后自定义交互(弹窗/链接/自定义代码) #### 1.92 1. 修复背景图预览适配问题 2. 转盘组件支持中奖后自定义交互/弹窗/自定义代码 3. 界面局部调整 4. 后台管理表单数据支持多键查询 5. 可视化大屏柱状图组件支持实时数据请求 ================================================ FILE: doc/zh/guide/deployDev/oss.md ================================================ **H5-Dooring**全面支持第三方对象存储服务, 我们以七牛云对象存储为例. ### 前端上传文件到 oss 首先我们需要在第三方对象储存服务中配置对应的服务和域名. 其次安装对应的 sdk, 如七牛云 sdk: ```js import * as qiniu from "qiniu-js"; ``` 其次我们修改`h5_plus`工程的`Upload`组件, 详细地址为`src/core/FormComponents/Upload`. 修改内容如下: ```js const fileName = file.name; const suffix = "自定义文件后缀"; const putExtra = { fname: fileName, params: {} }; const uid = +new Date() + uuid(16, 8) + suffix; // 使用七牛云上传api, 前提是提前在前端拿到对应的ticket, 可以通过请求的方式获取 const observe = qiniu.upload( file, uid, this.state.qnToken.ticket, putExtra, {} ); observe.subscribe( () => {}, null, res => { // 拼接路径 const url = `${this.state.qnToken.domain}/${res.key}`; // 存库 const fileList = [{ uid, name: fileName, status: "done", url }]; this.setState({ curImgUrl: url, fileList }); this.props.onChange && this.props.onChange(fileList); } ); ``` 其他 oss 服务类似, 如果不清楚如何配置, 可以在[H5-Dooring 官网](http://h5.dooring.cn/)中找到我们. ### 如何接入任何第三方上传服务 首先我们的上传组件`Upload`使用内部的服务接口来实现上传功能, 所以需要给组件的`action`赋值, 如下: ```jsx {fileList.length >= maxLen ? null : uploadButton} ``` 如果需要集成第三方 oss, 如七牛云, 阿里 oss 等, 我们需要将`Upload`组件的`action`属性设置为空字符串, 其次删除`onChange`属性, 上传操作统一在`beforeUpload`中进行. 案例如下: ```jsx {fileList.length >= maxLen ? null : uploadButton} ``` 自定义上传的核心逻辑放在了`beforeUpload`上. 我们具体看看`beforeUpload`这个方法如何实现. ```js handleBeforeUpload = (file: RcFile) => { // 1. 限制图片类型 const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png" || file.type === "image/jpg" || file.type === "image/gif"; if (!isJpgOrPng) { message.error("只能上传格式为jpeg/png/gif的图片"); } // 限制上传文件大小 const isLt3M = file.size / 1024 / 1024 < 3; if (!isLt3M) { message.error("图片必须小于3MB!"); } if (isJpgOrPng && isLt3M) { // 3. 正常上传逻辑 const fileName = file.name; // 3.1 调用oss接口, 将图片上传oss // 3.2 将接口返回的url信息, 组装成fileList数据结构, 并更新state const fileList = [{ uid, name: fileName, status: "done", url }]; this.setState({ curImgUrl: url, fileList }); // 3.3 将数据传给上层保存 this.props.onChange && this.props.onChange(fileList); } return isJpgOrPng && isLt3M; }; ``` ================================================ FILE: doc/zh/guide/directoryStructure.md ================================================ ``` src ├─ assets │ ├─ header.png │ ├─ form.png │ ├─ footer.png │ ├─ icon.png │ ├─ picture.png ├─ components │ ├─ BackTop │ │ └─ index.js │ ├─ BasicShop │ │ ├─ BasicComponents │ │ │ ├─ Card │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Carousel │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Footer │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Form │ │ │ │ ├─ BaseForm.tsx │ │ │ │ ├─ BasePopoverForm.tsx │ │ │ │ ├─ baseForm.less │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Header │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Icon │ │ │ │ ├─ icon.ts │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Image │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ LongText │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Nav │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Notice │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Qrcode │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ RichText │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Text │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ WhiteTpl │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ XButton │ │ │ │ ├─ Modal.tsx │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ schema.ts │ │ │ └─ template.ts │ │ ├─ MediaComponents │ │ │ ├─ Audio │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Calendar │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Map │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Video │ │ │ │ ├─ index.css │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ schema.ts │ │ │ └─ template.ts │ │ ├─ ShopComponents │ │ │ ├─ CardLabel │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Coupons │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ List │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Tab │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ ZhuanLan │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ schema.ts │ │ │ └─ template.ts │ │ ├─ VisualComponents │ │ │ ├─ Area │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Chart │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Funnel │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Line │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Pie │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ Radar │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ WordCloud │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ XProgress │ │ │ │ ├─ index.less │ │ │ │ ├─ index.tsx │ │ │ │ ├─ schema.ts │ │ │ │ └─ template.ts │ │ │ ├─ schema.ts │ │ │ └─ template.ts │ │ ├─ common.ts │ │ └─ schema.ts │ ├─ Calibration │ │ ├─ index.less │ │ └─ index.tsx │ ├─ ErrorBundaries │ │ └─ index.tsx │ ├─ LoadingCp │ │ └─ index.tsx │ ├─ ModalTpl │ │ ├─ cate.js │ │ ├─ index.js │ │ └─ index.less │ └─ Zan │ ├─ index.less │ └─ index.tsx ├─ core │ ├─ FormComponents │ │ ├─ CardPicker │ │ │ ├─ index.less │ │ │ └─ index.tsx │ │ ├─ Color │ │ │ ├─ index.less │ │ │ └─ index.tsx │ │ ├─ DataList │ │ │ ├─ editorModal.tsx │ │ │ ├─ index.less │ │ │ └─ index.tsx │ │ ├─ FormItems │ │ │ ├─ EditorModal.tsx │ │ │ ├─ FormItems.tsx │ │ │ ├─ formItems.less │ │ │ └─ index.tsx │ │ ├─ InteractionData │ │ │ ├─ index.less │ │ │ └─ index.tsx │ │ ├─ MutiText │ │ │ ├─ index.less │ │ │ └─ index.tsx │ │ ├─ Pos │ │ │ ├─ index.less │ │ │ └─ index.tsx │ │ ├─ Table │ │ │ ├─ index.less │ │ │ └─ index.tsx │ │ ├─ Upload │ │ │ ├─ index.less │ │ │ └─ index.tsx │ │ ├─ XEditor │ │ │ ├─ index.less │ │ │ └─ index.tsx │ │ └─ types.ts │ ├─ DynamicEngine.tsx │ ├─ FormRender.tsx │ ├─ ViewRender.tsx │ └─ viewRender.less ├─ layouts │ ├─ __tests__ │ │ └─ index.test.js │ ├─ index.less │ └─ index.tsx ├─ pages │ ├─ __tests__ │ │ └─ index.test.js │ ├─ editor │ │ ├─ components │ │ │ ├─ AvatorGroup │ │ │ │ └─ index.tsx │ │ │ ├─ CanvasControl │ │ │ │ ├─ index.less │ │ │ │ └─ index.tsx │ │ │ └─ Header │ │ │ ├─ index.js │ │ │ └─ index.less │ │ ├─ models │ │ │ └─ editorModal.js │ │ ├─ services │ │ │ └─ editorService.js │ │ ├─ Container.js │ │ ├─ SourceBox.tsx │ │ ├─ TargetBox.js │ │ ├─ index.js │ │ ├─ index.less │ │ └─ preview.tsx │ ├─ help │ │ ├─ index.less │ │ └─ index.tsx │ ├─ home │ │ ├─ index.less │ │ └─ index.tsx │ ├─ ide │ │ ├─ _draft.tsx │ │ ├─ index.less │ │ └─ index.tsx │ ├─ login │ │ ├─ index.less │ │ └─ index.tsx │ ├─ document.ejs │ └─ mobileTip.js ├─ utils │ ├─ req.ts │ └─ tool.ts ├─ app.tsx └─ global.css ``` ================================================ FILE: doc/zh/guide/functionRealization/download.md ================================================ ## 下载源码 目前 Dooring 已支持下载源码功能, 我们可以使用编辑器页面头部的下载按钮来实现下载用户搭建的 H5 源码. foo 源码下载之后是完整的 React 项目源代码, 开发人员可以直接根据自己的业务需求来二次编写代码来满足不同的业务需求. 在拿到源码之后, 我们需要进入项目, 使用 npm 或者 yarn 安装项目依赖, 如下: ```bash npm install // 或者 yarn ``` 之后我们就可以本地运行项目了: ```bash npm start // 或者 yarn start ``` 因为源码工程采用`umi3.0`搭建, 所以代码配置可以参考`umi3.0`规范, 比如路由配置, `history`模式, 打包路径等, 二次开发完成之后, 我们可以执行: ```bash npm run build // 或者 yarn build ``` 将项目打包成 html, 以便部署到任何服务器中. ================================================ FILE: doc/zh/guide/functionRealization/machinePreview.md ================================================ # 真机预览 真机预览和网页预览的流程类似,工作流程如下: foo 由于不同机型预览的效果有些许不同,最终效果以实际看到的为主。 ================================================ FILE: doc/zh/guide/functionRealization/pagePreview.md ================================================ # 网页预览 我们看看网页预览的工作流程: foo 前端预览界面: foo ================================================ FILE: doc/zh/guide/functionRealization/revocation.md ================================================ # 撤销/重做 撤销重做我们主要使用了 redux-undo 这个库,配合 Dva 使用,具体使用方法参考如下操作: ```js import { createLogger } from "redux-logger"; import { message } from "antd"; import undoable, { StateWithHistory } from "redux-undo"; import { Reducer, AnyAction } from "redux"; export const dva = { config: { onAction: createLogger(), onError(e: Error) { message.error(e.message, 3); }, onReducer: (reducer: Reducer) => { let undoReducer = undoable(reducer); return function(state: StateWithHistory, action: AnyAction) { let newState = undoReducer(state, action); let router = newState.present.router ? newState.present.router : newState.present.routing; return { ...newState, router: router }; }; } } }; ``` 以上我们就实现了全局配置 redux-undo,在撤销重做按钮中我们就可以触发对应的方法来实现撤销重做的功能,其次我们还使用了 redux-logger 来实现 redux 的日志输出。 ================================================ FILE: doc/zh/guide/functionRealization/saveJson.md ================================================ # 保存 json 我们配置好 H5 页面之后,如果希望其他人观看,我们可以保存页面并发送链接。但是如果有多人协作的需求,比如一个 H5 页面可能由多个人完成,这个时候该怎么实现呢?基于已有的方案,我们可以采用 socket 实现多人协同编辑,但是成本比较大,所有这里我们提供了保存 json 的功能。 我们可以将配置好的页面导出为 json,发送给另一个人,这样另一个人通过导入该 json 文件可以实时看到当前的页面,这里还是依靠我们的页面渲染引擎 viewEngine。实现思路也很简单,可以在 github[[https://github.com/MrXujiang/h5-Dooring](https://github.com/MrXujiang/h5-Dooring)]上参考体验。 ================================================ FILE: doc/zh/guide/functionRealization/screenshot.md ================================================ # 截图功能 截图功能这里我们主要使用了 dom-to-image 这个库,来将 html 转化为图片,并进行分享。 foo ================================================ FILE: doc/zh/guide/functionRealization/templateLibrary.md ================================================ ## 模板库实现思路 我们目前开放了模板库功能,一方面我们会定期配置行业模板,另一个方面 Dooring 还支持用户自己配置模板,可以一键保存到云端供用户使用。我们也可以将模板变成自己的页面共享给其他人。实现方式本质上是保存用户的配置信息,上传到服务器中做存储,在后台提供了管理模板的模块,可以修改,删除模板。如下图所示: ### 模板前台展示: foo ### 模板后台展示: foo ================================================ FILE: doc/zh/guide/introduced.md ================================================ foo 注:灰色部分还未实现,正在更新中... ================================================ FILE: doc/zh/guide/startedQuickly.md ================================================ # 快速上手 ## 从零搭建一个 H5 表单页面 ## 环境准备 首先得有 node,并确保 node 版本是 `10.13` 或以上,(mac/win 下推荐使用 n 来管理 node 版本) ``` $ node-v v10.13.0 ``` 注:推荐使用 yarn 管理 npm 依赖 ## 源码工程 | h5_plus(编辑器项目) | admin(管理后台) | Server(服务端项目) | | ------------------- | --------------- | ------------------ | 本地拿到源码工程之后先安装对应依赖,在对应工程目录里执行 yarn 命令,等待依赖安装完成。 ## 本地运行 1.首先本地启动 server,在 src 目录的 index.js 中修改跨域白名单,改为本地的 ip+端口,如http://192.167.0.3:8000 2.其次本地启动 h5_plus,启动完毕在浏览器打开对应的启动地址即可查看,如下: foo ================================================ FILE: package.json ================================================ { "name": "h5-dooring", "version": "1.3.0", "description": "H5-Dooring是一款功能强大,开源免费的H5可视化页面配置解决方案,致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。技术栈以react为主, 后台采用nodejs开发。", "private": false, "author": { "name": "徐小夕", "email": "xujiang156@qq.com", "url": "http://h5.dooring.cn/h5_visible" }, "keywords": [ "h5 editor", "h5", "react", "antd", "react-dnd", "web visible" ], "contributors": [ "徐小夕 (https://github.com/MrXujiang))", "mokinzhao <37622852@qq.com> (https://github.com/mokinzhao))", "yehuozhili (https://github.com/yehuozhili))" ], "scripts": { "start": "export NODE_OPTIONS=--openssl-legacy-provider && umi dev -- editor", "start:win": "set NODE_OPTIONS=--openssl-legacy-provider && umi dev -- editor", "build": "export NODE_OPTIONS=--openssl-legacy-provider && umi build", "build:win": "set NODE_OPTIONS=--openssl-legacy-provider && umi build", "server": "node server.js", "dev": "http-server dist", "docs:dev": "vuepress dev doc", "docs:build": "vuepress build doc", "test-demo": "http-server dist", "postinstall": "umi generate tmp", "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'", "test": "umi-test", "test:coverage": "umi-test --coverage", "nocompress": "cross-env RM_TMPDIR=none COMPRESS=none umi build" }, "gitHooks": { "pre-commit": "lint-staged" }, "lint-staged": { "*.{js,jsx,less,md,json}": [ "prettier --write" ], "*.ts?(x)": [ "prettier --parser=typescript --write" ] }, "homepage": "http://h5.dooring.cn", "repository": { "type": "git", "url": "git+https://github.com/MrXujiang/h5-Dooring.git" }, "bugs": { "url": "https://github.com/MrXujiang/h5-Dooring/issues" }, "dependencies": { "@ant-design/icons": "^4.2.1", "@antv/f2": "^3.7.7", "@visactor/vchart": "^1.12.1", "@uiw/react-baidu-map": "^1.17.3", "@umijs/plugin-esbuild": "^1.0.1", "@umijs/plugin-sass": "^1.1.1", "@umijs/preset-react": "1.x", "@umijs/test": "^3.2.19", "antd": "^4.7.0", "antd-img-crop": "^3.10.0", "axios": "^0.19.2", "braft-editor": "^2.3.9", "chatbot-antd": "^0.6.0", "codemirror": "^5.57.0", "dom-to-image": "^2.6.0", "file-saver": "^2.0.2", "http-server": "^0.12.3", "keymaster": "^1.6.2", "qrcode.react": "^1.0.0", "react": "^16.12.0", "react-audio-player": "^0.14.0", "react-codemirror2": "^7.2.1", "react-color": "^2.18.1", "react-contexify": "^4.1.1", "react-dnd": "^11.1.3", "react-dnd-html5-backend": "^11.1.3", "react-dom": "^16.12.0", "react-draggable": "^4.4.3", "react-draggable-ball": "^0.1.0", "react-grid-layout": "^1.0.0", "react-hotkeys-hook": "^2.3.1", "react-text-loop": "^2.3.0", "redux-undo": "^1.0.1", "socket.io-client": "^2.3.0", "umi": "^3.2.19", "video-react": "^0.14.1", "xlsx": "^0.16.7", "yh-react-popover": "^0.3.0", "yorkie": "^2.0.0", "zarm": "^2.5.1" }, "license": "GPL-3.0", "devDependencies": { "@types/classnames": "^2.2.10", "@types/codemirror": "^0.0.98", "@types/events": "^3.0.0", "@types/file-saver": "^2.0.1", "@types/node": "^14.6.2", "@types/qrcode.react": "^1.0.1", "@types/react-color": "^3.0.4", "@types/react-grid-layout": "^1.1.0", "@types/redux-logger": "^3.0.8", "@types/xlsx": "^0.0.36", "@typescript-eslint/eslint-plugin": "4.1.1", "@typescript-eslint/parser": "4.1.1", "babel-eslint": "10.x", "babel-plugin-import": "^1.13.0", "cross-env": "^7.0.2", "eslint": "6.x", "eslint-config-react-app": "^5.2.1", "eslint-plugin-flowtype": "4.x", "eslint-plugin-import": "2.x", "eslint-plugin-jsx-a11y": "6.x", "eslint-plugin-react": "7.x", "eslint-plugin-react-hooks": "2.x", "koa": "^2.13.0", "koa-body": "^4.2.0", "koa-logger": "^3.2.1", "koa-static": "^5.0.0", "koa2-cors": "^2.0.6", "lint-staged": "^10.0.7", "prettier": "^1.19.1", "redux-logger": "^3.0.6", "sass-loader": "^9.0.3", "typescript": "^4.0.2", "vuepress": "^1.8.0" } } ================================================ FILE: readme.md ================================================ > > Make H5 as easy as building blocks!

H5编辑器,H5制作神器,H5 editor,lowcode

Welcome to H5-Dooring 👋

Version Documentation license:GPL3.0

> H5-Dooring is a powerful, open source, free H5 visual page configuration solution dedicated to providing a simple, convenient, professional and reliable, unlimited set of H5 landing page best practices. The technology stack is mainly react, developed in the background using nodejs. H5-Dooring编辑器预览图 | home🏠 | demo✨ | doc📦 | tutorial | wiki | | ------------------------------- | ------------------------------------ | ------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------- | | [website](https://dooring.vip) | [Demo](https://dooring.vip) | [Document](https://dooring.vip/doc) | [视频&Video](https://www.zhihu.com/zvideo/1406394315950653440) | [wiki](https://github.com/MrXujiang/h5-Dooring/wiki) | > ✨ note: If the official visit is too slow, visit the [H5-Dooring for Singapore](https://dooring.vip) 🎉福利🎉: 最近基于nextjs实现的多维表格正式上线, 前100名用户仅需399元, 感兴趣可以参考体验一下. - 多维表格编辑器: http://pxcharts.com English | [简体中文](./zh.md) new doc: [private deployment process](http://h5.dooring.cn/docz/source-list/H5-Dooring/deploy_en) website: [H5-Dooring](https://dooring.net) tech blog: [sharing of technology](https://dev.to/alex_xu/we-made-a-page-visualization-to-build-an-open-source-project-1l1p) Related products: - [V6.Dooring | Large screen visual editor](https://github.com/MrXujiang/v6.dooring.public) - [dooring-electron-lowcode | Dooring desktop software](https://github.com/MrXujiang/dooring-electron-lowcode) - [flowmix/docx | 多模态文档引擎](http://flowmix.tunrtip.cn/docx) - [Dooring-Saas](https://dooring.vip) - [Dooring 智图](https://magic.dooring.vip) ## Author 👤 **alex_xu** - Website: http://h5.dooring.cn - Github: [@MrXujiang](https://github.com/MrXujiang) - new tech share: [Dooring2.7+最新技术分享&复盘](https://github.com/MrXujiang/h5-Dooring/issues/145) ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=MrXujiang/h5-Dooring&type=Date)](https://star-history.com/#MrXujiang/h5-Dooring&Date) ## 🤝 Contributing and support Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/MrXujiang/h5-Dooring/issues). Give a ⭐️ if this project helped you! ## Privatization Deployment documentation - address: http://h5.dooring.cn/docz - ⭐️ lowcode component list: http://h5.dooring.cn/docz/components/intro - List of answers: http://h5.dooring.cn/docz/source-list/H5-Dooring/guide - gitee mini code: https://gitee.com/lowcode-china/h5_-dooring ### Features 1. editor - [x] Guides - [x] The underlying component - [x] Visual components - [x] Media components - [x] Product components - [x] Dragper - [x] Configure the panel - [x] Form designer - [x] (Multi) Page management (copy, edit, delete, new) - [x] Component animation - [x] Component interaction - [x] Data source management - [x] Quick preview - [x] Real machine preview - [x] Undo and redo - [x] WeChat shares - [x] shortcut key - [x] The template library - [x] Desktop software, Dooring-electron, supports offline use 2) Enhanced features - [x] Upload json, convert to H5 with one click - [x] Photo gallery - [x] Code capability (download source, download dis package) 3) backend API - [x] Create, save, and update your work - [x] User management, rights management - [x] One-click intelligent analysis - [x] Data look - [x] Form data collection - [x] Form data presentation - [x] Form data analysis, one-click export excel, form multi-condition search - [x] Preview online - [x] QR code preview - [x] Template management - [x] Code interface ## Update the log 1. Whether the video component adds a full-screen configuration item when playing 2. Fixes a click failure of the icon component 3. The editor supports multi-size switching and canvas size customization 4. Fix multilingual issues with background management analytics forms 5. The component library supports user-defined selection ## Technology Sharing - [(10 月最新) 前端图形学实战: 从零开发几何画板(vue3 + vite 版](https://github.com/MrXujiang/h5-Dooring/issues/149) - [几何学在前端边界计算中的应用和原理分析(一)](https://github.com/MrXujiang/h5-Dooring/issues/148) ### The back-end section The back-end part because of the knowledge points involved is more, is not the focus of this article, so here is a few points, you can use completely different technology to achieve back-office services, such as PHP, Java, Python or Egg. The author here is using the "koa" . Specific code can refer to the full stack development article: - [基于 Koa + React + TS 从零开发全栈文档编辑器](https://mp.weixin.qq.com/s?__biz=MzU2Mzk1NzkwOA==&mid=2247486910&idx=2&sn=7ce865dd8a8f6769439f0e8eebb72212&chksm=fc531445cb249d534a7d8a362ad40d26bc90f2d2e867385768ee19575e32826fcbe419fcbe0b&token=297396546&lang=zh_CN#rd) - [Dooring 后台接口文档](http://h5.dooring.cn/doc/zh/guide/deployDev/api.html) - [私有化部署](http://h5.dooring.cn/h5_plus/price) ## Install 1. Download the code ```sh git clone https://github.com/MrXujiang/h5-Dooring.git ``` 2. Go to the project catalog ```sh cd ./h5-Dooring ``` 3. Install the dependency package ```sh yarn pkg ``` ## Usage Launch the app locally ```sh yarn start or cnpm run start ``` local visit: ``` http://localhost:port/h5_plus ``` 注意: 如果 window 系统下无法启动, 请移步 [dooring-electron](https://github.com/H5-Dooring/dooring-electron-lowcode) ## How to run the downloaded code ? 1. The compression package can be unzipped directly to the server root, and access to the root address is sufficient 2. 'vscode' installs the Live Server plug-in, unzips the downloaded compression package into a folder, opens with 'vscode', clicks on Live Server, and notes that to remove the 'index .html' of the startup path, change it to '/' If you find that the local boot component drag and drop encountered strange errors, is the third-party component in the development environment bug, you can take a step to solve: > If you find that the local start-up component drag encountered strange errors, is a bug that should be a third-party component in the development environment, can be resolved in a way: ```sh yarn dev or cnpm run dev ``` The premise is to install the http-server module first. ## Browsers support Modern browsers does not support IE browser | [IE / Edge](https://godban.github.io/browsers-support-badges/)
IEdge | [Firefox](https://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](https://godban.github.io/browsers-support-badges/)
Chrome | [Safari](https://godban.github.io/browsers-support-badges/)
Safari | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Edge | last 2 versions | last 2 versions | last 2 versions | ## Contact us line Twitter Account:@H5Dooring ## Partner project - [ react-cropper-pro - 轻量强大的图片上传/裁切/压缩组件](https://github.com/MrXujiang/react-cropper-pro) - [mitu-editor - 轻量级且强大的图片编辑器](https://github.com/H5-Dooring/mitu-editor) - [powerNice - 一款轻量级文档管理编辑器](http://h5.dooring.cn/powernice/views) - [rc-drag - 基于 react 的轻量级拖拽缩放组件](https://github.com/MrXujiang/rc-drag) - [ t-nav - 开箱即用的开源导航项目](https://github.com/MrXujiang/t-nav) - [Luckysheet - 强大的在线 excel 编辑器](https://github.com/mengshukeji/Luckysheet) - [Blink - 一款自定义的生成故障艺术动画的组件库](https://github.com/MrXujiang/blink) - [frontend-developer-roadmap | 一个能提高开发者工作效率的前端 js 库汇总](https://github.com/MrXujiang/frontend-developer-roadmap) * [react-form-simple - 基于 react 开发的高性能表单库](https://github.com/easy-form/react-form-simple) * [lucky-canvas 抽奖插件 | 一个支持 H5, 微信小程序, React 的抽奖插件](https://github.com/LuckDraw/lucky-canvas) * [vue-admin-box | 免费并且开源的中后台管理系统模板](https://github.com/cmdparkour/vue-admin-box) * [基于 antd 开箱即用的后台管理模版 ant-simple-pro](https://github.com/lgf196/ant-simple-pro) * [使用 gin+vue 进行极速开发的全栈开发基础平台](https://github.com/flipped-aurora/gin-vue-admin) * [DevUI 中后台产品开源前端解决方案](https://github.com/DevCloudFE/ng-devui) ## Sponsored Open source is not easy, with your sponsorship, we will do better ## Technical feedback and communication wechat:beautifulFront ================================================ FILE: server.js ================================================ const Koa = require("koa"); const { resolve } = require("path"); const staticServer = require("koa-static"); const koaBody = require("koa-body"); const cors = require("koa2-cors"); const logger = require("koa-logger"); const app = new Koa(); app.use(staticServer(resolve(__dirname, "./static"))); app.use(koaBody()); app.use(logger()); // 设置跨域 app.use( cors({ origin: function(ctx) { if (ctx.url.indexOf("/dooring") > -1) { return "*"; // 允许来自所有域名请求 } return ""; }, exposeHeaders: ["WWW-Authenticate", "Server-Authorization", "x-test-code"], maxAge: 5, // 该字段可选,用来指定本次预检请求的有效期,单位为秒 credentials: true, allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], allowHeaders: [ "Content-Type", "Authorization", "Accept", "x-requested-with", "Content-Encoding" ] }) ); let htmlStr = ""; app.use(async (ctx, next) => { console.log(ctx.url); if (ctx.url === "/dooring/render") { htmlStr = ctx.request.body; ctx.body = "success"; } else if (ctx.url.indexOf("/html") === 0) { ctx.type = "html"; ctx.body = htmlStr; } }); app.listen(3000); ================================================ FILE: src/app.tsx ================================================ import { createLogger } from "redux-logger"; import { message } from "antd"; import undoable, { StateWithHistory } from "redux-undo"; import { Reducer, AnyAction } from "redux"; export const dva = { config: { [process.env.NODE_ENV === "development" ? "onAction" : ""]: createLogger(), onError(e: Error) { message.error(e.message, 3); }, onReducer: (reducer: Reducer) => { let undoReducer = undoable(reducer); return function(state: StateWithHistory, action: AnyAction) { let newState = undoReducer(state, action); let router = newState.present.router ? newState.present.router : newState.present.routing; return { ...newState, router: router }; }; } } }; ================================================ FILE: src/components/Calibration/index.less ================================================ .calibration { width: calc(200% - 50px); height: 200%; position: relative; white-space: nowrap; pointer-events: none; user-select: none; :global(.calibrationNumber) { font-size: 12px; color: #888; } } ================================================ FILE: src/components/Calibration/index.tsx ================================================ import React, { useState, useEffect, useRef, useCallback } from "react"; import styles from "./index.less"; export interface calibrationTypes { width: number; height: number; } export type CalibrationTypes = { direction: "up" | "left" | "right"; multiple: number; id: string; }; export default function Calibration(props: CalibrationTypes) { const { direction, multiple } = props; const [calibrationLength, setCalibration] = useState({ width: 0, height: 0 }); const calibrationRef = useRef(null); const generateElement = useCallback( (item?: boolean, num?: number) => { if (calibrationRef.current) { let createSpan = document.createElement("div"); createSpan.className = "calibrationLine"; createSpan.style.backgroundColor = "#ccc"; calibrationRef.current.style.display = "flex"; calibrationRef.current.style.justifyContent = "space-between"; if (direction === "up") { calibrationRef.current.style.marginLeft = "50px"; createSpan.style.width = "1px"; createSpan.style.height = "6px"; createSpan.style.display = "inline-block"; } else { calibrationRef.current.style.flexDirection = "column"; createSpan.style.height = "1px"; createSpan.style.width = "6px"; } if (item) { let createSpanContent = document.createElement("span"); if (direction === "up") { createSpan.style.height = "12px"; createSpanContent.style.transform = "translate3d(-4px, 20px, 0px)"; createSpan.style.transform = "translateY(0px)"; } else { createSpan.style.width = "12px"; createSpanContent.style.paddingLeft = "20px"; } createSpanContent.style.display = "block"; createSpanContent.className = "calibrationNumber"; createSpanContent.innerHTML = num! * 5 + ""; createSpan.appendChild(createSpanContent); } calibrationRef.current.appendChild(createSpan); } }, [direction] ); useEffect(() => { if (calibrationRef.current) { let calibration = calibrationRef.current.getBoundingClientRect(); setCalibration({ width: calibration.width, height: calibration.height }); let length = direction === "up" ? calibration.width : calibration.height; for (let i = 0; i < length / 5; i++) { if (i % 10 === 0) { generateElement(true, i); } else { generateElement(); } } } }, [direction, generateElement]); useEffect(() => { if (calibrationRef.current) { let width = calibrationLength.width ? calibrationLength.width : calibrationRef.current.getBoundingClientRect().width; let height = calibrationLength.height ? calibrationLength.height : calibrationRef.current.getBoundingClientRect().height; let arr = [ ...Array.from( calibrationRef.current.querySelectorAll(".calibrationLine") ) ]; if (arr.length) { if (direction === "up") { calibrationRef.current.style.width = parseFloat(multiple.toFixed(1)) * width + "px"; arr.forEach(el => { let dom = [ ...Array.from(el.querySelectorAll(".calibrationNumber")) ][0] as HTMLElement; if (dom) { dom.style.transform = `translate3d(-4px, 16px, 0px) scale(${( multiple + 0.1 ).toFixed(1)})`; } }); } else { calibrationRef.current.style.height = parseFloat(multiple.toFixed(1)) * height + "px"; arr.forEach(el => { let dom = [ ...Array.from(el.querySelectorAll(".calibrationNumber")) ][0] as HTMLElement; if (dom) { dom.style.transform = `translate3d(-4px, -8px, 0px) scale(${( multiple + 0.1 ).toFixed(1)})`; } }); } } } }, [calibrationLength.height, calibrationLength.width, direction, multiple]); return
; } ================================================ FILE: src/components/ErrorBundaries/index.tsx ================================================ import React, { ErrorInfo, PropsWithChildren } from "react"; interface ErrorBoundaryState { hasError: boolean; } class ErrorBoundary extends React.Component< PropsWithChildren<{}>, ErrorBoundaryState > { constructor(props: PropsWithChildren<{}>) { super(props); this.state = { hasError: false }; } componentDidCatch(_error: Error, _info: ErrorInfo) { // Display fallback UI this.setState({ hasError: true }); // You can also log the error to an error reporting service //logErrorToMyService(error, info); } render() { if (this.state.hasError) { // You can render any custom fallback UI return

Something went wrong.

; } return this.props.children; } } export default ErrorBoundary; ================================================ FILE: src/components/FormComponents/CardPicker/index.less ================================================ .pickerWrap { display: flex; flex-wrap: wrap; .picker { display: inline-block; padding: 10px; border: 2px solid transparent; cursor: pointer; &:hover { border-color: #4091f7; } &.selected { border-color: #4091f7; } } } ================================================ FILE: src/components/FormComponents/CardPicker/index.tsx ================================================ import { useState, useEffect, memo } from "react"; import classnames from "classnames"; import Icon from "@/materials/base/Icon"; import styles from "./index.less"; import React from "react"; import { IconTypes } from "@/materials/base/Icon/schema"; import { ICardPickerConfigType } from "../types"; interface CardPickerType extends Omit, "type" | "key" | "name"> { onChange?: (v: string) => void; type: IconTypes; } export default memo((props: CardPickerType) => { const { type, icons, onChange } = props; const [selected, setSelected] = useState(type); const handlePicker = (v: IconTypes) => { if (onChange) { onChange(v); return; } setSelected(v); }; useEffect(() => { setSelected(type); }, [type]); return (
{icons.map((item, i) => { return ( handlePicker(item)} key={i} > ); })}
); }); ================================================ FILE: src/components/FormComponents/Color/index.tsx ================================================ import React from "react"; import { SketchPicker, ColorResult } from "react-color"; import { rgba2Obj } from "@/utils/tool"; export type ColorConfigType = string; //value 初始值传来,onchange item给的回调 interface ColorProps { value?: ColorConfigType; onChange?: (v: ColorConfigType) => void; } class colorPicker extends React.Component { state = { displayColorPicker: false, color: rgba2Obj(this.props.value) }; handleClick = () => { this.setState({ displayColorPicker: !this.state.displayColorPicker }); }; handleClose = () => { this.setState({ displayColorPicker: false }); }; handleChange = (color: ColorResult) => { this.setState({ color: color.rgb }); this.props.onChange && this.props.onChange( `rgba(${color.rgb.r},${color.rgb.g},${color.rgb.b},${color.rgb.a})` ); }; render() { return (
{this.state.displayColorPicker ? (
) : null}
); } } export default colorPicker; ================================================ FILE: src/components/FormComponents/DataList/editorModal.tsx ================================================ import React, { memo, useEffect, FC } from "react"; import { Form, Select, Input, Modal, Button } from "antd"; import Upload from "../Upload"; import { Store } from "antd/lib/form/interface"; import { TDataListDefaultTypeItem } from "../FormEditor/types"; // import styles from './index.less'; const normFile = (e: any) => { if (Array.isArray(e)) { return e; } return e && e.fileList; }; const { Option } = Select; const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 14 } }; export type EditorModalProps = { visible: boolean; onCancel: | ((e: React.MouseEvent) => void) | undefined; item?: TDataListDefaultTypeItem; onSave: Function; cropRate: number; }; const EditorModal: FC = props => { const { item, onSave, visible, onCancel, cropRate } = props; const onFinish = (values: Store) => { console.log(values); onSave && onSave(values); }; const handleOk = () => { form .validateFields() .then(values => { if (item) { values.id = item.id; onSave && onSave(values); } }) .catch(err => { console.log(err); }); }; const [form] = Form.useForm(); useEffect(() => { if (form && item && visible) { form.resetFields(); } }, [form, item, visible]); return ( <> {!!item && ( handleOk()}> 确定 } >
{!!window["currentCates"] && ( )}
)} ); }; export default memo(EditorModal); ================================================ FILE: src/components/FormComponents/DataList/index.less ================================================ .dataList { padding: 6px 10px; border: 1px solid #f0f0f0; text-align: justify; padding-left: 10px; padding-top: 10px; } .listItem { position: relative; padding-bottom: 6px; margin-bottom: 6px; border-bottom: 1px solid #f0f0f0; &:hover { .actionBar { display: block; } } &:last-child { border-bottom: none; margin-bottom: 0; } .tit { font-weight: bold; padding-bottom: 5px; } .desc { font-size: 12px; color: #ccc; } .actionBar { position: absolute; right: 0; top: 50%; transform: translateY(-50%); display: none; background: #fff; box-shadow: -20px 0 10px 10px #fff; .action { margin-right: 18px; cursor: pointer; &:last-child { cursor: move; } } } } ================================================ FILE: src/components/FormComponents/DataList/index.tsx ================================================ import React, { memo, useState, useEffect, useCallback } from "react"; import { EditOutlined, MinusCircleOutlined, MenuOutlined } from "@ant-design/icons"; import { Button } from "antd"; import { DragSource, DropTarget, DndProvider, ConnectDropTarget, DragSourceSpec, DropTargetConnector, DragSourceMonitor, DragSourceConnector, DropTargetSpec, ConnectDragSource, ConnectDragPreview } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; import EditorModal from "./editorModal"; import { uuid } from "@/utils/tool"; import styles from "./index.less"; import { TDataListDefaultType, TDataListDefaultTypeItem } from "../types"; type ListItemProps = DndItemProps & { isDragging: boolean; connectDragSource: ConnectDragSource; connectDragPreview: ConnectDragPreview; connectDropTarget: ConnectDropTarget; }; function ListItem(props: ListItemProps) { const { title, desc, onDel, onEdit, // 这些 props 由 React DnD注入,参考`collect`函数定义 isDragging, connectDragSource, connectDragPreview, connectDropTarget } = props; const opacity = isDragging ? 0.5 : 1; return connectDropTarget( // 列表项本身作为 Drop 对象 connectDragPreview( // 整个列表项作为跟随拖动的影像
{title}
{desc}
onEdit()}> onDel()}> {connectDragSource( ) // 拖动图标作为 Drag 对象 }
) ); } type DndItemProps = TDataListDefaultTypeItem & { onDel: Function; onEdit: Function; key: number; find: Function; move: Function; type?: number; }; const type = "item"; type DragObject = { id: string; originalIndex: number; }; const dragSpec: DragSourceSpec = { // 拖动开始时,返回描述 source 数据。后续通过 monitor.getItem() 获得 beginDrag: props => ({ id: props.id, originalIndex: props.find(props.id).index }), // 拖动停止时,处理 source 数据 endDrag(props, monitor) { const { id: droppedId, originalIndex } = monitor.getItem(); const didDrop = monitor.didDrop(); // source 是否已经放置在 target if (!didDrop) { return props.move(droppedId, originalIndex); } } }; const dragCollect = ( connect: DragSourceConnector, monitor: DragSourceMonitor ) => ({ connectDragSource: connect.dragSource(), // 用于包装需要拖动的组件 connectDragPreview: connect.dragPreview(), // 用于包装需要拖动跟随预览的组件 isDragging: monitor.isDragging() // 用于判断是否处于拖动状态 }); const dropSpec: DropTargetSpec = { canDrop: () => false, // item 不处理 drop hover(props, monitor) { const { id: draggedId } = monitor.getItem(); const { id: overId } = props; // 如果 source item 与 target item 不同,则交换位置并重新排序 if (draggedId !== overId) { const { index: overIndex } = props.find(overId); props.move(draggedId, overIndex); } } }; const dropCollect = (connect: DropTargetConnector) => ({ connectDropTarget: connect.dropTarget() // 用于包装需接收拖拽的组件 }); const DndItem = DropTarget( type, dropSpec, dropCollect )(DragSource(type, dragSpec, dragCollect)(ListItem)); export type DataListMemo = { onChange?: (v: TDataListDefaultType) => void; value?: TDataListDefaultType; cropRate: number; }; export type DataListType = DataListMemo & { connectDropTarget: ConnectDropTarget; }; const List = function(props: DataListType) { const { onChange, value, connectDropTarget, cropRate } = props; const [list, setList] = useState(value); const [visible, setVisible] = useState(false); const [curItem, setCurItem] = useState(); const handleDel = (id: string) => { if (value && onChange) { let newVal = value.filter(item => id !== item.id); onChange(newVal); } }; const find = (id: string) => { const item = list!.find(c => `${c.id}` === id)!; return { item, index: list!.indexOf(item!) }; }; const move = (id: string, toIndex: number) => { const { item, index } = find(id); const oldList = [...list!]; oldList.splice(index, 1); oldList.splice(toIndex, 0, item); if (onChange) { onChange(oldList); return; } setList(oldList); }; const handleCancel = useCallback(() => { console.log("a"); setVisible(false); }, []); const handleEdit = useCallback((item: TDataListDefaultTypeItem) => { console.log("b"); setVisible(true); setCurItem(item); }, []); const handleSave = useCallback( (item: TDataListDefaultTypeItem) => { console.log("c"); setVisible(false); if (onChange) { onChange(list!.map(p => (p.id === item.id ? item : p))); return; } setList(prev => prev!.map(p => (p.id === item.id ? item : p))); }, [list, onChange] ); const handleAdd = () => { const item = { title: "新增项标题", desc: "新增项描述", id: uuid(8, 10), imgUrl: [], link: "" }; if (onChange) { onChange([...list!, item]); return; } setList([...list!, item]); }; useEffect(() => { setList(value); }, [value]); return connectDropTarget(
{!!(list && list.length) && list.map((item, i) => ( handleDel(item.id)} onEdit={() => handleEdit(item)} key={i} id={`${item.id}`} find={find} move={move} /> ))}
); }; const DndList = DropTarget(type, {}, connect => ({ connectDropTarget: connect.dropTarget() }))(List); // 将 HTMLBackend 作为参数传给 DragDropContext export default memo((props: DataListMemo) => { return ( ); }); ================================================ FILE: src/components/FormComponents/FormItems/EditorModal.tsx ================================================ import React, { FC, memo, useEffect } from "react"; import { Form, Select, Input, Modal, Button, InputNumber } from "antd"; import { baseFormOptionsType } from "../types"; import Color from "../Color"; const { Option } = Select; const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 14 } }; interface EditorModalProps { item: any; onSave: (data: any) => void; visible: boolean; } const EditorModal: FC = props => { const { item, onSave, visible } = props; const onFinish = (values: any) => { onSave && onSave(values); }; const handleOk = () => { form .validateFields() .then(values => { values.id = item.id; onSave && onSave(values); }) .catch(err => { console.log(err); }); }; const [form] = Form.useForm(); useEffect(() => { if (form && item && visible) { form.resetFields(); } }, [form, item, visible]); return ( <> {!!item && (
} forceRender visible={visible} onOk={handleOk} closable={false} >
{ } {!!item.label && ( )} {!!item.fontSize && ( )} {!!item.color && ( )} {!!item.placeholder && ( )} {!!item.options && ( )}
)} ); }; export default memo(EditorModal); ================================================ FILE: src/components/FormComponents/FormItems/FormItems.tsx ================================================ import React, { memo, RefObject, useCallback, useEffect, useState } from "react"; import BaseForm from "@/materials/base/Form/BaseForm"; import BasePopoverForm from "@/materials/base/Form/BasePopoverForm"; import EditorModal from "./EditorModal"; import { MinusCircleFilled, EditFilled, PlusOutlined } from "@ant-design/icons"; import styles from "./formItems.less"; import { baseFormUnion, TFormItemsDefaultType } from "../types"; import { uuid } from "@/utils/tool"; import { Button } from "antd"; import MyPopover from "yh-react-popover"; // import { Popconfirm } from 'antd'; const formTpl: TFormItemsDefaultType = [ { id: "1", type: "Text", label: "文本框", placeholder: "请输入文本" }, { id: "2", type: "Textarea", label: "长文本框", placeholder: "请输入长文本请输入长文本" }, { id: "3", type: "Number", label: "数值", placeholder: " 请输入数值" }, { id: "4", type: "MyRadio", label: "单选框", options: [ { label: "选项一", value: "1" }, { label: "选项二", value: "2" } ] }, { id: "5", type: "MySelect", label: "下拉选择框", options: [ { label: "选项一", value: "1" }, { label: "选项二", value: "2" }, { label: "选项三", value: "3" } ] }, { id: "6", type: "Date", label: "日期框", placeholder: "" }, { id: "7", type: "MyTextTip", label: "纯文本", fontSize: 12, color: "rgba(0,0,0,1)" } ]; interface FormItemsProps { formList?: TFormItemsDefaultType; onChange?: (v: TFormItemsDefaultType) => void; data: any; rightPannelRef: RefObject; } const FormItems = (props: FormItemsProps) => { const { formList, onChange, rightPannelRef } = props; const [formData, setFormData] = useState( formList || [] ); const [visible, setVisible] = useState(false); const [curItem, setCurItem] = useState(); const [force, setforce] = useState<{ force: Function }>({ force: () => {} }); const handleAddItem = (item: baseFormUnion) => { let tpl = formTpl.find(v => v.type === item.type); let newData = [...formData, { ...tpl!, id: uuid(6, 10) }]; setFormData(newData); onChange && onChange(newData); force.force(); }; const handleEditItem = (item: baseFormUnion) => { setVisible(true); setCurItem(item); }; const handleDelItem = (item: baseFormUnion) => { let newData = formData.filter(v => v.id !== item.id); setFormData(newData); onChange && onChange(newData); }; const handleSaveItem = (data: baseFormUnion) => { let newData = formData.map(v => (v.id === data.id ? data : v)); setFormData(newData); onChange && onChange(newData); setVisible(false); }; const callback = useCallback((v: Function) => { console.log(v); setforce({ force: v }); }, []); useEffect(() => { let listenner: (e: Event) => void; if (rightPannelRef.current) { listenner = () => { force.force(); }; rightPannelRef.current.addEventListener("scroll", listenner); } return () => { if (rightPannelRef.current) { // eslint-disable-next-line react-hooks/exhaustive-deps rightPannelRef.current.removeEventListener("scroll", listenner); } }; }, [force, rightPannelRef]); return (
表单控件
{formData.map((item: baseFormUnion, i: number) => { let FormItem = BaseForm[item.type]; return (
handleDelItem(item)} >
handleEditItem(item)} >
); })}
{formTpl.map((item, i) => { let FormItem = BasePopoverForm[item.type]; return (
handleAddItem(item)} >
); })}
{/* setFormTplVisible(false)}>Close */} } directions={"LB"} innerConstDomStyle={{ display: "block" }} constDomStyle={{ display: "block" }} callback={callback} >
); }; export default memo(FormItems); ================================================ FILE: src/components/FormComponents/FormItems/formItems.less ================================================ .formItemWrap { .formTitle { width: 56px; height: 20px; font-size: 14px; font-family: PingFangSC-Medium, PingFang SC; font-weight: bold; color: #000000; line-height: 20px; } .editForm { text-align: left; width: 251px; .formItem { position: relative; padding-left: 2px; .common { position: absolute; top: 19px; box-shadow: 0 0 20px #fff; .operationBtn { margin-right: 15px; display: inline-block; cursor: pointer; } } .deleteWrap { .common; left: 0; } .editWrap { .common; right: -18px; } } .formAddWrap { font-size: 14px; font-weight: 400; color: #4a4a4a; line-height: 20px; background-color: #2f54eb; } } .formAddWrap { .formTpl { margin-top: 12px; border-top: 1px dashed #ccc; padding-top: 16px; background-color: #4a4a4a; .formItem { button, [type="button"] { color: #fff; background-color: #4a4a4a; border: 1px solid #fff; border-radius: 4px 0px 0px 0px; } position: relative; border: 1px solid #ccc; margin-bottom: 2px; background-color: #4a4a4a; cursor: pointer; .disClick { pointer-events: none; color: #fff; } &:hover { border-color: #2f54eb; .addBtn { display: inline-block; } } .addBtn { position: absolute; right: 0; top: 50%; transform: translateY(-50%); display: none; padding: 3px 6px; color: #fff; border-radius: 3px; background-color: #2f54eb; cursor: pointer; } } } } } ================================================ FILE: src/components/FormComponents/FormItems/index.tsx ================================================ import FormItems from "./FormItems"; export default FormItems; ================================================ FILE: src/components/FormComponents/MutiText/index.less ================================================ .mutiText { .iptWrap { margin-bottom: 12px; display: flex; .delBtn { // font-size: 14px; margin-left: 12px; cursor: pointer; align-self: center; } } } ================================================ FILE: src/components/FormComponents/MutiText/index.tsx ================================================ import React, { memo, useEffect } from "react"; import { Input, Button, Popconfirm } from "antd"; import { MinusCircleFilled } from "@ant-design/icons"; import styles from "./index.less"; import { TMutiTextDefaultType } from "../types"; type MultiTextProps = { onChange?: (v: TMutiTextDefaultType) => void; value?: TMutiTextDefaultType; }; export default memo(function MutiText(props: MultiTextProps) { const { value, onChange } = props; const handleAdd = () => { onChange && onChange([...value!, "新增项目"]); }; const handleDel = (index: number) => { let newList = value!.filter((_item, i) => i !== index); onChange && onChange(newList); }; const handleChange = ( index: number, e: React.ChangeEvent ) => { let newList = value!.map((item, i) => i === index ? e.target.value : item ); onChange && onChange(newList); }; useEffect(() => { window["currentCates"] = value!; return () => { window["currentCates"] = null; }; }, [value]); return (
{value && value.length ? ( value!.map((item, i) => { return (
handleChange(i, e)} /> handleDel(i)} placement="leftTop" okText="确定" cancelText="取消" >
); }) ) : (
)} {value && value.length < 3 && (
)}
); }); ================================================ FILE: src/components/FormComponents/Pos/index.less ================================================ .posIpt { display: flex; justify-content: flex-end; margin-right: -10px; .posItem { margin-right: 10px; span { margin-right: 3px; } } } ================================================ FILE: src/components/FormComponents/Pos/index.tsx ================================================ import React, { memo, useState, useEffect } from "react"; import { InputNumber } from "antd"; import styles from "./index.less"; import { TPosDefaultType, TPosItem } from "../types"; type PosProps = { value?: TPosDefaultType; onChange?: (v: TPosItem | string) => void; }; export default memo(function Pos(props: PosProps) { const { value, onChange } = props; let _this: typeof Pos = Pos; const handleChange = (index: number, v: TPosItem | string) => { let arr: any = value || []; arr[index] = v; onChange && onChange(arr); }; return (
x:
y:
); }); ================================================ FILE: src/components/FormComponents/Table/index.less ================================================ :global(.editable-cell) { position: relative; } :global(.editable-cell-value-wrap) { padding: 5px 12px; cursor: pointer; } :global(.editable-row) { &:hover :global(.editable-cell-value-wrap) { border: 1px solid #d9d9d9; border-radius: 4px; padding: 4px 11px; } } :global([data-theme="dark"]) { :global(.editable-row) { &:hover { :global(.editable-cell-value-wrap) { border: 1px solid #434343; } } } } .apiForm { .formItem { margin-bottom: 16px; } } ================================================ FILE: src/components/FormComponents/Table/index.tsx ================================================ import React, { useContext, useState, useEffect, useRef, memo, RefObject } from "react"; import { Table, Input, Button, Popconfirm, Form, Modal, Upload } from "antd"; import { ColumnsType } from "antd/lib/table"; import { uuid } from "@/utils/tool"; import XLSX from "xlsx"; // 下方样式主要为全局样式,暂时不可删 import styles from "./index.less"; const EditableContext = React.createContext(null); interface Item { key: string; name: string; age: string; address: string; } interface EditableRowProps { index: number; } const EditableRow: React.FC = ({ index, ...props }) => { const [form] = Form.useForm(); return (
); }; interface EditableCellProps { title: React.ReactNode; editable: boolean; children: React.ReactNode; dataIndex: string; record: any; handleSave: (record: Item) => void; } const EditableCell: React.FC = ({ title, editable, children, dataIndex, record, handleSave, ...restProps }) => { const [editing, setEditing] = useState(false); const inputRef = useRef(null); const form = useContext(EditableContext); useEffect(() => { if (editing) { inputRef.current?.focus(); } }, [editing]); const toggleEdit = () => { setEditing(!editing); form.setFieldsValue({ [dataIndex]: record[dataIndex] }); }; const save = async () => { try { const values = await form.validateFields(); toggleEdit(); handleSave({ ...record, ...values }); } catch (errInfo) { console.log("Save failed:", errInfo); } }; let childNode = children; if (editable) { childNode = editing ? ( RefObject} onPressEnter={save} onBlur={save} /> ) : (
{children}
); } return {childNode}; }; class EditableTable extends React.Component { columns: ( | { title: string; dataIndex: string; width: string; editable: boolean; render?: undefined; } | { title: string; dataIndex: string; render: (text: string, record: any) => JSX.Element | null; width?: undefined; editable?: undefined; } )[]; apiForm: { api: string; header: string; dataField: string; }; constructor(props: any) { super(props); this.columns = [ { title: "名字", dataIndex: "name", width: "180px", editable: true }, { title: "值", dataIndex: "value", width: "120px", editable: true }, { title: "操作", dataIndex: "operation", render: (text: string, record) => this.state.dataSource.length >= 1 ? ( this.handleDelete(record.key)} > ) : null } ]; this.apiForm = { api: "", header: "", dataField: "" }; const dataSource = props.data && props.data.map((item: any, i: number) => ({ key: i + "", ...item })); this.state = { dataSource: dataSource, visible: false, apiVisible: false, apiResult: "" }; } handleDelete = (key: string) => { const dataSource = [...this.state.dataSource]; const newDataSource = dataSource.filter(item => item.key !== key); this.setState({ dataSource: newDataSource }); this.props.onChange && this.props.onChange(newDataSource); }; handleAdd = () => { const { dataSource } = this.state; const uid = uuid(8, 10); const newData = { key: uid, name: `dooring ${dataSource.length + 1}`, value: 32 }; const newDataSource = [...dataSource, newData]; this.setState({ dataSource: newDataSource }); this.props.onChange && this.props.onChange(newDataSource); }; handleSave = (row: any) => { const newData = [...this.state.dataSource]; const index = newData.findIndex(item => row.key === item.key); const item = newData[index]; newData.splice(index, 1, { ...item, ...row }); this.setState({ dataSource: newData }); this.props.onChange && this.props.onChange(newData); }; showModal = () => { this.setState({ visible: true }); }; handleOk = (e: React.MouseEvent) => { this.setState({ visible: false }); }; handleCancel = (e: React.MouseEvent) => { this.setState({ visible: false }); }; showApiModal = () => { this.setState({ apiVisible: true }); }; handleAPIOk = () => { const { dataField } = this.apiForm; if (dataField) { let data = this.state.apiResult[dataField]; if (data && data instanceof Array) { data = data.map((item, i) => ({ key: i + "", ...item })); this.setState({ dataSource: data }); this.props.onChange && this.props.onChange(data); } this.setState({ apiVisible: false }); } }; handleAPICancel = () => { this.setState({ apiVisible: false }); }; handleApiField = (type: "api" | "header" | "dataField", v: string) => { this.apiForm[type] = v; }; getApiFn = () => { console.log(this.apiForm); const { api, header } = this.apiForm; fetch(api, { cache: "no-cache", headers: Object.assign( { "content-type": "application/json" }, header ? JSON.parse(header) : {} ), method: "GET", mode: "cors" }) .then(res => res.json()) .then(res => { this.setState({ apiResult: res }); }); }; render() { const { dataSource } = this.state; const components = { body: { row: EditableRow, cell: EditableCell } }; const columns: ColumnsType = this.columns.map(col => { if (!col.editable) { return col; } return { ...col, onCell: record => ({ record, editable: col.editable, dataIndex: col.dataIndex, title: col.title, handleSave: this.handleSave }) }; }); const _this = this; const props = { name: "file", // action: '', showUploadList: false, beforeUpload(file: File, fileList: Array) { // 解析并提取excel数据 let reader = new FileReader(); reader.onload = function(e: any) { let data = e.target.result; let workbook = XLSX.read(data, { type: "binary" }); let sheetNames = workbook.SheetNames; // 工作表名称集合 let draftArr: any = {}; sheetNames.forEach(name => { let worksheet = workbook.Sheets[name]; // 只能通过工作表名称来获取指定工作表 for (let key in worksheet) { // v是读取单元格的原始值 if (key[0] !== "!") { if (draftArr[key[0]]) { draftArr[key[0]].push(worksheet[key].v); } else { draftArr[key[0]] = [worksheet[key].v]; } } } }); let sourceData = Object.values(draftArr).map((item: any, i) => ({ key: i + "", name: item[0], value: item[1] })); _this.setState({ dataSource: sourceData }); _this.props.onChange && _this.props.onChange(sourceData); }; reader.readAsBinaryString(file); } }; return (
"editable-row"} bordered dataSource={dataSource} columns={columns} pagination={{ pageSize: 50 }} scroll={{ y: 240 }} />
this.handleApiField("api", e.target.value)} />
this.handleApiField("header", e.target.value)} />
{this.state.apiResult && ( <>
this.handleApiField("dataField", e.target.value) } />

数据源字段是接口返回的图表数据对应的字段, 必填, 否则无法正确导入数据

)}
); } } export default memo(EditableTable); ================================================ FILE: src/components/FormComponents/Upload/index.less ================================================ :global(.ant-upload-select-picture-card i) { color: #999; font-size: 14px; } :global(.ant-upload-select-picture-card .ant-upload-text) { margin-top: 8px; color: #666; } .avatarUploader { display: inline-block; text-align: left; } .wallBtn { position: absolute; left: 140px; bottom: 56px; display: inline-block; color: #2f54eb; cursor: pointer; border-bottom: 1px solid #2f54eb; } .imgBox { display: flex; flex-wrap: wrap; max-height: 520px; overflow: auto; .imgItem { position: relative; margin-right: 16px; margin-bottom: 16px; width: 320px; max-height: 220px; overflow: hidden; cursor: pointer; img { width: 100%; } &:hover, &.seleted { .iconBtn { visibility: visible; } } .iconBtn { position: absolute; visibility: hidden; top: 6px; right: 10px; font-size: 18px; color: rgb(8, 156, 8); } } } ================================================ FILE: src/components/FormComponents/Upload/index.tsx ================================================ import React from "react"; import { Upload, Modal, message, Tabs, Result } from "antd"; import { PlusOutlined, CheckCircleFilled } from "@ant-design/icons"; import ImgCrop from "antd-img-crop"; import classnames from "classnames"; import { UploadFile, UploadChangeParam, RcFile } from "antd/lib/upload/interface"; import { isDev, unParams, uuid } from "@/utils/tool"; import req from "@/utils/req"; import styles from "./index.less"; const { TabPane } = Tabs; // 维护图片分类映射 const wallCateName: any = { photo: "照片", bg: "背景", chahua: "插画" }; function getBase64(file: File | Blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result as string); reader.onerror = error => reject(error); }); } interface PicturesWallType { fileList?: UploadFile[]; action?: string; headers?: any; withCredentials?: boolean; maxLen?: number; onChange?: (v: any) => void; cropRate?: number | boolean; isCrop?: boolean; } class PicturesWall extends React.Component { state = { previewVisible: false, previewImage: "", wallModalVisible: false, previewTitle: "", imgBed: { photo: [], bg: [], chahua: [] }, curSelectedImg: "", fileList: this.props.fileList || [] }; handleCancel = () => this.setState({ previewVisible: false }); handleModalCancel = () => this.setState({ wallModalVisible: false }); handlePreview = async (file: UploadFile) => { if (!file.url && !file.preview) { file.preview = await getBase64(file.originFileObj!); } this.setState({ previewImage: file.url || file.preview, previewVisible: true, previewTitle: file.name || file.url!.substring(file.url!.lastIndexOf("/") + 1) }); }; handleWallSelect = (url: string) => { this.setState({ wallModalVisible: true }); }; handleImgSelected = (url: string) => { this.setState({ curSelectedImg: url }); }; handleWallShow = () => { this.setState({ wallModalVisible: true }); }; handleModalOk = () => { const fileList = [ { uid: uuid(8, 16), name: "h5-dooring图片库", status: "done", url: this.state.curSelectedImg } ]; this.props.onChange && this.props.onChange(fileList); this.setState({ fileList, wallModalVisible: false }); }; handleChange = ({ file, fileList }: UploadChangeParam>) => { this.setState({ fileList }); if (file.status === "done") { const files = fileList.map(item => { const { uid, name, status } = item; const url = item.url || item.response.result.url; return { uid, name, status, url }; }); this.props.onChange && this.props.onChange(files); } }; handleBeforeUpload = (file: RcFile) => { const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png" || file.type === "image/jpg" || file.type === "image/gif"; if (!isJpgOrPng) { message.error("只能上传格式为jpeg/png/gif的图片"); } const isLt2M = file.size / 1024 / 1024 < 2; if (!isLt2M) { message.error("图片必须小于2MB!"); } return isJpgOrPng && isLt2M; }; componentDidMount() { // req.get(`/visible/bed/get?tid=${unParams(location.search)!.tid}`).then(res => { // res && // this.setState({ // imgBed: res, // }); // }); } render() { const { previewVisible, previewImage, fileList, previewTitle, wallModalVisible, imgBed, curSelectedImg } = this.state; const { action = isDev ? "http://192.168.1.8:3000/api/v0/files/upload/free" : "你的服务器地址", headers, withCredentials = true, maxLen = 1, cropRate = 375 / 158, isCrop } = this.props; const uploadButton = (
上传
); const cates = Object.keys(imgBed); return ( <> {isCrop ? ( {fileList.length >= maxLen ? null : uploadButton} ) : ( {fileList.length >= maxLen ? null : uploadButton} )}
图片库
预览图片 {cates.map((item, i) => { return (
{(imgBed as any)[item] && (imgBed as any)[item].map((item: string, i: number) => { return (
this.handleImgSelected(item)} > 趣谈前端-h5-dooring
); })}
); })}
); } } export default PicturesWall; ================================================ FILE: src/components/FormComponents/XEditor/index.less ================================================ .avatarUploader > :global(.ant-upload) { width: 128px; height: 128px; } ================================================ FILE: src/components/FormComponents/XEditor/index.tsx ================================================ import React, { useState, useEffect, memo } from "react"; import req from "@/utils/req"; import BraftEditor from "braft-editor"; import "braft-editor/dist/index.css"; import styles from "./index.less"; const controls = [ { key: "bold", text: 加粗 }, "undo", "redo", "emoji", "list-ul", "list-ol", "blockquote", "text-align", "font-size", "line-height", "letter-spacing", "text-color", "italic", "underline", "link", "media" ]; export default memo(function XEditor(props: any) { const { value, onChange } = props; const [editorState, setEditorState] = useState( BraftEditor.createEditorState(value) ); const myUploadFn = (param: any) => { const fd = new FormData(); fd.append("file", param.file); req .post("xxxx", fd, { headers: { "Content-Type": "multipart/form-data" }, onUploadProgress: function(event) { // 上传进度发生变化时调用param.progress console.log((event.loaded / event.total) * 100); param.progress((event.loaded / event.total) * 100); } }) .then((res: any) => { // 上传成功后调用param.success并传入上传后的文件地址 param.success({ url: res.url, meta: { id: Date.now(), title: res.filename, alt: "趣谈前端" } }); }) .catch(err => { param.error({ msg: "上传失败." }); }); }; const submitContent = () => { const htmlContent = editorState.toHTML(); onChange && onChange(htmlContent); }; const handleEditorChange = editorState => { setEditorState(editorState); if (onChange) { const htmlContent = editorState.toHTML(); onChange(htmlContent); } }; useEffect(() => { const htmlContent = value || ""; setEditorState(BraftEditor.createEditorState(htmlContent)); }, []); return ( ); }); ================================================ FILE: src/components/FormComponents/types.ts ================================================ //////////////////// export interface IUploadConfigType { key: string; name: string; type: "Upload"; isCrop?: boolean; cropRate?: number; } export type TUploadDefaultType = Array<{ uid: string; name: string; status: string; url: string; }>; ///////////////// export interface ITextConfigType { key: string; name: string; type: "Text"; } export type TTextDefaultType = string; //////////////////////// export interface ITextAreaConfigType { key: string; name: string; type: "TextArea"; } export type TTextAreaDefaultType = string; //////////////////////////// export interface INumberConfigType { key: string; name: string; type: "Number"; range?: [number, number]; step?: number; } export type TNumberDefaultType = number; /////////////////// export interface IDataListConfigType { key: string; name: string; type: "DataList"; cropRate: number; } export type TDataListDefaultTypeItem = { id: string; title: string; desc: string; link: string; type?: number; imgUrl: TUploadDefaultType; }; export type TDataListDefaultType = Array; //////////////////// export interface IColorConfigType { key: string; name: string; type: "Color"; } export type TColorDefaultType = string; ///////////////// export interface IRichTextConfigType { key: string; name: string; type: "RichText"; } export type TRichTextDefaultType = string; export interface IMutiTextConfigType { key: string; name: string; type: "MutiText"; } export type TMutiTextDefaultType = Array; ///////////////////////////////// export interface ISelectConfigType { key: string; name: string; type: "Select"; range: Array<{ key: KeyType; text: string; }>; } export type TSelectDefaultType = KeyType; ///////////////////////// export interface IRadioConfigType { key: string; name: string; type: "Radio"; range: Array<{ key: KeyType; text: string; }>; } export type TRadioDefaultType = KeyType; /////////////// export interface ISwitchConfigType { key: string; name: string; type: "Switch"; } export type TSwitchDefaultType = boolean; ///////////////////////////// export interface ICardPickerConfigType { key: string; name: string; type: "CardPicker"; icons: Array; } export type TCardPickerDefaultType = T; ///////////// export interface ITableConfigType { key: string; name: string; type: "Table"; } export type TTableDefaultType = Array<{ name: string; value: number; }>; // position input control export interface IPosConfigType { key: string; name: string; type: "Pos"; placeObj: { text: string; link: string; }; } export type TPosItem = number | undefined; export type TPosDefaultType = [TPosItem, TPosItem]; ////////////////// export interface IFormItemsConfigType { key: string; name: string; type: "FormItems"; } //0---------baseform export type baseFormOptionsType = { label: string; value: string; }; export type baseFormTextTpl = { id: string; type: "Text"; label: string; placeholder: string; }; export type baseFormTextTipTpl = { id: string; type: "MyTextTip"; label: string; color: string; fontSize: number; }; export type baseFormNumberTpl = { id: string; type: "Number"; label: string; placeholder: string; }; export type baseFormTextAreaTpl = { id: string; type: "Textarea"; label: string; placeholder: string; }; export type baseFormMyRadioTpl = { id: string; type: "MyRadio"; label: string; options: baseFormOptionsType[]; }; export type baseFormMyCheckboxTpl = { id: string; type: "MyCheckbox"; label: string; options: baseFormOptionsType[]; }; export type baseFormMySelectTpl = { id: string; type: "MySelect"; label: string; options: baseFormOptionsType[]; }; export type baseFormDateTpl = { id: string; type: "Date"; label: string; placeholder: string; }; export type baseFormUnion = | baseFormTextTpl | baseFormTextTipTpl | baseFormNumberTpl | baseFormTextAreaTpl | baseFormMyRadioTpl | baseFormMyCheckboxTpl | baseFormMySelectTpl | baseFormDateTpl; export type baseFormUnionType = | baseFormTextTpl["type"] | baseFormTextTipTpl["type"] | baseFormNumberTpl["type"] | baseFormTextAreaTpl["type"] | baseFormMyRadioTpl["type"] | baseFormMyCheckboxTpl["type"] | baseFormMySelectTpl["type"] | baseFormDateTpl["type"]; export type TFormItemsDefaultType = Array; ================================================ FILE: src/components/LoadingCp/index.tsx ================================================ import React from "react"; export default () =>
Dooring
; ================================================ FILE: src/components/Zan/index.less ================================================ .takeCat { display: inline-block; } .imgWrap { width: 160px; img { width: 100%; } } ================================================ FILE: src/components/Zan/index.tsx ================================================ import React, { memo } from "react"; import { Button, Popover } from "antd"; import styles from "./index.less"; interface IProps { text: any; } ///这组件写的有问题 popover会重定位 const content = (
sponsorship
); export default memo(function ZanPao(props: IProps) { const { text = ( ) } = props; return (
{text}
); }); ================================================ FILE: src/core/DynamicEngine.tsx ================================================ import { dynamic } from "umi"; import Loading from "../components/LoadingCp"; import { useMemo, memo, FC } from "react"; import React from "react"; export type componentsType = "media" | "base" | "visible" | "shop"; const DynamicFunc = (type: string, componentsType: string) => { return dynamic({ loader: async function() { const { default: Graph } = await import( `@/materials/${componentsType}/${type}` ); const Component = Graph; return (props: DynamicType) => { const { config, isTpl } = props; return ; }; }, loading: () => (
) }); }; type DynamicType = { isTpl: boolean; config: { [key: string]: any }; type: string; componentsType: componentsType; category: string; }; const DynamicEngine = memo((props: DynamicType) => { const { type, config, category } = props; const Dynamic = useMemo(() => { return (DynamicFunc(type, category) as unknown) as FC; // eslint-disable-next-line react-hooks/exhaustive-deps }, [config]); return ; }); export default DynamicEngine; ================================================ FILE: src/core/index.ts ================================================ import DynamicEngine from "./DynamicEngine"; import ViewRender from "./renderer/ViewRender"; import FormRender from "./renderer/FormRender"; export { DynamicEngine, ViewRender, FormRender }; ================================================ FILE: src/core/renderer/FormRender.tsx ================================================ import React, { memo, RefObject, useEffect } from "react"; import { Form, Select, InputNumber, Input, Switch, Radio } from "antd"; import Upload from "../../components/FormComponents/Upload"; import DataList from "../../components/FormComponents/DataList"; import MutiText from "../../components/FormComponents/MutiText"; import Color from "../../components/FormComponents/Color"; import CardPicker from "../../components/FormComponents/CardPicker"; import Table from "../../components/FormComponents/Table"; import Pos from "../../components/FormComponents/Pos"; import { Store } from "antd/lib/form/interface"; import RichText from "../../components/FormComponents/XEditor"; import FormItems from "../../components/FormComponents/FormItems"; const normFile = (e: any) => { console.log("Upload event:", e); if (Array.isArray(e)) { //待修改 return e; } return e && e.fileList; }; const { Option } = Select; const { TextArea } = Input; const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } }; interface FormEditorProps { uid: string; onSave: Function; onDel: Function; defaultValue: { [key: string]: any }; config: Array; rightPannelRef: RefObject; } const FormEditor = (props: FormEditorProps) => { const { config, defaultValue, onSave, uid, rightPannelRef } = props; const onFinish = (values: Store) => { onSave && onSave(values); }; const [form] = Form.useForm(); useEffect(() => { return () => { form.resetFields(); }; }, [uid, form]); const handlechange = () => { onFinish(form.getFieldsValue()); }; return (
{config.map((item, i) => { return ( {item.type === "Number" && ( )} {item.type === "Text" && ( )} {item.type === "TextArea" && (
================================================ FILE: website/js/jquery.js ================================================ /*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ !(function(e, t) { 'use strict'; 'object' == typeof module && 'object' == typeof module.exports ? (module.exports = e.document ? t(e, !0) : function(e) { if (!e.document) throw new Error('jQuery requires a window with a document'); return t(e); }) : t(e); })('undefined' != typeof window ? window : this, function(C, e) { 'use strict'; var t = [], E = C.document, r = Object.getPrototypeOf, s = t.slice, g = t.concat, u = t.push, i = t.indexOf, n = {}, o = n.toString, v = n.hasOwnProperty, a = v.toString, l = a.call(Object), y = {}, m = function(e) { return 'function' == typeof e && 'number' != typeof e.nodeType; }, x = function(e) { return null != e && e === e.window; }, c = { type: !0, src: !0, nonce: !0, noModule: !0 }; function b(e, t, n) { var r, i, o = (n = n || E).createElement('script'); if (((o.text = e), t)) for (r in c) (i = t[r] || (t.getAttribute && t.getAttribute(r))) && o.setAttribute(r, i); n.head.appendChild(o).parentNode.removeChild(o); } function w(e) { return null == e ? e + '' : 'object' == typeof e || 'function' == typeof e ? n[o.call(e)] || 'object' : typeof e; } var f = '3.4.1', k = function(e, t) { return new k.fn.init(e, t); }, p = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; function d(e) { var t = !!e && 'length' in e && e.length, n = w(e); return ( !m(e) && !x(e) && ('array' === n || 0 === t || ('number' == typeof t && 0 < t && t - 1 in e)) ); } (k.fn = k.prototype = { jquery: f, constructor: k, length: 0, toArray: function() { return s.call(this); }, get: function(e) { return null == e ? s.call(this) : e < 0 ? this[e + this.length] : this[e]; }, pushStack: function(e) { var t = k.merge(this.constructor(), e); return (t.prevObject = this), t; }, each: function(e) { return k.each(this, e); }, map: function(n) { return this.pushStack( k.map(this, function(e, t) { return n.call(e, t, e); }), ); }, slice: function() { return this.pushStack(s.apply(this, arguments)); }, first: function() { return this.eq(0); }, last: function() { return this.eq(-1); }, eq: function(e) { var t = this.length, n = +e + (e < 0 ? t : 0); return this.pushStack(0 <= n && n < t ? [this[n]] : []); }, end: function() { return this.prevObject || this.constructor(); }, push: u, sort: t.sort, splice: t.splice, }), (k.extend = k.fn.extend = function() { var e, t, n, r, i, o, a = arguments[0] || {}, s = 1, u = arguments.length, l = !1; for ( 'boolean' == typeof a && ((l = a), (a = arguments[s] || {}), s++), 'object' == typeof a || m(a) || (a = {}), s === u && ((a = this), s--); s < u; s++ ) if (null != (e = arguments[s])) for (t in e) (r = e[t]), '__proto__' !== t && a !== r && (l && r && (k.isPlainObject(r) || (i = Array.isArray(r))) ? ((n = a[t]), (o = i && !Array.isArray(n) ? [] : i || k.isPlainObject(n) ? n : {}), (i = !1), (a[t] = k.extend(l, o, r))) : void 0 !== r && (a[t] = r)); return a; }), k.extend({ expando: 'jQuery' + (f + Math.random()).replace(/\D/g, ''), isReady: !0, error: function(e) { throw new Error(e); }, noop: function() {}, isPlainObject: function(e) { var t, n; return ( !(!e || '[object Object]' !== o.call(e)) && (!(t = r(e)) || ('function' == typeof (n = v.call(t, 'constructor') && t.constructor) && a.call(n) === l)) ); }, isEmptyObject: function(e) { var t; for (t in e) return !1; return !0; }, globalEval: function(e, t) { b(e, { nonce: t && t.nonce }); }, each: function(e, t) { var n, r = 0; if (d(e)) { for (n = e.length; r < n; r++) if (!1 === t.call(e[r], r, e[r])) break; } else for (r in e) if (!1 === t.call(e[r], r, e[r])) break; return e; }, trim: function(e) { return null == e ? '' : (e + '').replace(p, ''); }, makeArray: function(e, t) { var n = t || []; return ( null != e && (d(Object(e)) ? k.merge(n, 'string' == typeof e ? [e] : e) : u.call(n, e)), n ); }, inArray: function(e, t, n) { return null == t ? -1 : i.call(t, e, n); }, merge: function(e, t) { for (var n = +t.length, r = 0, i = e.length; r < n; r++) e[i++] = t[r]; return (e.length = i), e; }, grep: function(e, t, n) { for (var r = [], i = 0, o = e.length, a = !n; i < o; i++) !t(e[i], i) !== a && r.push(e[i]); return r; }, map: function(e, t, n) { var r, i, o = 0, a = []; if (d(e)) for (r = e.length; o < r; o++) null != (i = t(e[o], o, n)) && a.push(i); else for (o in e) null != (i = t(e[o], o, n)) && a.push(i); return g.apply([], a); }, guid: 1, support: y, }), 'function' == typeof Symbol && (k.fn[Symbol.iterator] = t[Symbol.iterator]), k.each( 'Boolean Number String Function Array Date RegExp Object Error Symbol'.split(' '), function(e, t) { n['[object ' + t + ']'] = t.toLowerCase(); }, ); var h = (function(n) { var e, d, b, o, i, h, f, g, w, u, l, T, C, a, E, v, s, c, y, k = 'sizzle' + 1 * new Date(), m = n.document, S = 0, r = 0, p = ue(), x = ue(), N = ue(), A = ue(), D = function(e, t) { return e === t && (l = !0), 0; }, j = {}.hasOwnProperty, t = [], q = t.pop, L = t.push, H = t.push, O = t.slice, P = function(e, t) { for (var n = 0, r = e.length; n < r; n++) if (e[n] === t) return n; return -1; }, R = 'checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped', M = '[\\x20\\t\\r\\n\\f]', I = '(?:\\\\.|[\\w-]|[^\0-\\xa0])+', W = '\\[' + M + '*(' + I + ')(?:' + M + '*([*^$|!~]?=)' + M + '*(?:\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)"|(' + I + '))|)' + M + '*\\]', $ = ':(' + I + ')(?:\\(((\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)")|((?:\\\\.|[^\\\\()[\\]]|' + W + ')*)|.*)\\)|)', F = new RegExp(M + '+', 'g'), B = new RegExp('^' + M + '+|((?:^|[^\\\\])(?:\\\\.)*)' + M + '+$', 'g'), _ = new RegExp('^' + M + '*,' + M + '*'), z = new RegExp('^' + M + '*([>+~]|' + M + ')' + M + '*'), U = new RegExp(M + '|>'), X = new RegExp($), V = new RegExp('^' + I + '$'), G = { ID: new RegExp('^#(' + I + ')'), CLASS: new RegExp('^\\.(' + I + ')'), TAG: new RegExp('^(' + I + '|[*])'), ATTR: new RegExp('^' + W), PSEUDO: new RegExp('^' + $), CHILD: new RegExp( '^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(' + M + '*(even|odd|(([+-]|)(\\d*)n|)' + M + '*(?:([+-]|)' + M + '*(\\d+)|))' + M + '*\\)|)', 'i', ), bool: new RegExp('^(?:' + R + ')$', 'i'), needsContext: new RegExp( '^' + M + '*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(' + M + '*((?:-\\d)?\\d*)' + M + '*\\)|)(?=[^-]|$)', 'i', ), }, Y = /HTML$/i, Q = /^(?:input|select|textarea|button)$/i, J = /^h\d$/i, K = /^[^{]+\{\s*\[native \w/, Z = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, ee = /[+~]/, te = new RegExp('\\\\([\\da-f]{1,6}' + M + '?|(' + M + ')|.)', 'ig'), ne = function(e, t, n) { var r = '0x' + t - 65536; return r != r || n ? t : r < 0 ? String.fromCharCode(r + 65536) : String.fromCharCode((r >> 10) | 55296, (1023 & r) | 56320); }, re = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, ie = function(e, t) { return t ? '\0' === e ? '\ufffd' : e.slice(0, -1) + '\\' + e.charCodeAt(e.length - 1).toString(16) + ' ' : '\\' + e; }, oe = function() { T(); }, ae = be( function(e) { return !0 === e.disabled && 'fieldset' === e.nodeName.toLowerCase(); }, { dir: 'parentNode', next: 'legend' }, ); try { H.apply((t = O.call(m.childNodes)), m.childNodes), t[m.childNodes.length].nodeType; } catch (e) { H = { apply: t.length ? function(e, t) { L.apply(e, O.call(t)); } : function(e, t) { var n = e.length, r = 0; while ((e[n++] = t[r++])); e.length = n - 1; }, }; } function se(t, e, n, r) { var i, o, a, s, u, l, c, f = e && e.ownerDocument, p = e ? e.nodeType : 9; if (((n = n || []), 'string' != typeof t || !t || (1 !== p && 9 !== p && 11 !== p))) return n; if (!r && ((e ? e.ownerDocument || e : m) !== C && T(e), (e = e || C), E)) { if (11 !== p && (u = Z.exec(t))) if ((i = u[1])) { if (9 === p) { if (!(a = e.getElementById(i))) return n; if (a.id === i) return n.push(a), n; } else if (f && (a = f.getElementById(i)) && y(e, a) && a.id === i) return n.push(a), n; } else { if (u[2]) return H.apply(n, e.getElementsByTagName(t)), n; if ((i = u[3]) && d.getElementsByClassName && e.getElementsByClassName) return H.apply(n, e.getElementsByClassName(i)), n; } if ( d.qsa && !A[t + ' '] && (!v || !v.test(t)) && (1 !== p || 'object' !== e.nodeName.toLowerCase()) ) { if (((c = t), (f = e), 1 === p && U.test(t))) { (s = e.getAttribute('id')) ? (s = s.replace(re, ie)) : e.setAttribute('id', (s = k)), (o = (l = h(t)).length); while (o--) l[o] = '#' + s + ' ' + xe(l[o]); (c = l.join(',')), (f = (ee.test(t) && ye(e.parentNode)) || e); } try { return H.apply(n, f.querySelectorAll(c)), n; } catch (e) { A(t, !0); } finally { s === k && e.removeAttribute('id'); } } } return g(t.replace(B, '$1'), e, n, r); } function ue() { var r = []; return function e(t, n) { return r.push(t + ' ') > b.cacheLength && delete e[r.shift()], (e[t + ' '] = n); }; } function le(e) { return (e[k] = !0), e; } function ce(e) { var t = C.createElement('fieldset'); try { return !!e(t); } catch (e) { return !1; } finally { t.parentNode && t.parentNode.removeChild(t), (t = null); } } function fe(e, t) { var n = e.split('|'), r = n.length; while (r--) b.attrHandle[n[r]] = t; } function pe(e, t) { var n = t && e, r = n && 1 === e.nodeType && 1 === t.nodeType && e.sourceIndex - t.sourceIndex; if (r) return r; if (n) while ((n = n.nextSibling)) if (n === t) return -1; return e ? 1 : -1; } function de(t) { return function(e) { return 'input' === e.nodeName.toLowerCase() && e.type === t; }; } function he(n) { return function(e) { var t = e.nodeName.toLowerCase(); return ('input' === t || 'button' === t) && e.type === n; }; } function ge(t) { return function(e) { return 'form' in e ? e.parentNode && !1 === e.disabled ? 'label' in e ? 'label' in e.parentNode ? e.parentNode.disabled === t : e.disabled === t : e.isDisabled === t || (e.isDisabled !== !t && ae(e) === t) : e.disabled === t : 'label' in e && e.disabled === t; }; } function ve(a) { return le(function(o) { return ( (o = +o), le(function(e, t) { var n, r = a([], e.length, o), i = r.length; while (i--) e[(n = r[i])] && (e[n] = !(t[n] = e[n])); }) ); }); } function ye(e) { return e && 'undefined' != typeof e.getElementsByTagName && e; } for (e in ((d = se.support = {}), (i = se.isXML = function(e) { var t = e.namespaceURI, n = (e.ownerDocument || e).documentElement; return !Y.test(t || (n && n.nodeName) || 'HTML'); }), (T = se.setDocument = function(e) { var t, n, r = e ? e.ownerDocument || e : m; return ( r !== C && 9 === r.nodeType && r.documentElement && ((a = (C = r).documentElement), (E = !i(C)), m !== C && (n = C.defaultView) && n.top !== n && (n.addEventListener ? n.addEventListener('unload', oe, !1) : n.attachEvent && n.attachEvent('onunload', oe)), (d.attributes = ce(function(e) { return (e.className = 'i'), !e.getAttribute('className'); })), (d.getElementsByTagName = ce(function(e) { return e.appendChild(C.createComment('')), !e.getElementsByTagName('*').length; })), (d.getElementsByClassName = K.test(C.getElementsByClassName)), (d.getById = ce(function(e) { return ( (a.appendChild(e).id = k), !C.getElementsByName || !C.getElementsByName(k).length ); })), d.getById ? ((b.filter.ID = function(e) { var t = e.replace(te, ne); return function(e) { return e.getAttribute('id') === t; }; }), (b.find.ID = function(e, t) { if ('undefined' != typeof t.getElementById && E) { var n = t.getElementById(e); return n ? [n] : []; } })) : ((b.filter.ID = function(e) { var n = e.replace(te, ne); return function(e) { var t = 'undefined' != typeof e.getAttributeNode && e.getAttributeNode('id'); return t && t.value === n; }; }), (b.find.ID = function(e, t) { if ('undefined' != typeof t.getElementById && E) { var n, r, i, o = t.getElementById(e); if (o) { if ((n = o.getAttributeNode('id')) && n.value === e) return [o]; (i = t.getElementsByName(e)), (r = 0); while ((o = i[r++])) if ((n = o.getAttributeNode('id')) && n.value === e) return [o]; } return []; } })), (b.find.TAG = d.getElementsByTagName ? function(e, t) { return 'undefined' != typeof t.getElementsByTagName ? t.getElementsByTagName(e) : d.qsa ? t.querySelectorAll(e) : void 0; } : function(e, t) { var n, r = [], i = 0, o = t.getElementsByTagName(e); if ('*' === e) { while ((n = o[i++])) 1 === n.nodeType && r.push(n); return r; } return o; }), (b.find.CLASS = d.getElementsByClassName && function(e, t) { if ('undefined' != typeof t.getElementsByClassName && E) return t.getElementsByClassName(e); }), (s = []), (v = []), (d.qsa = K.test(C.querySelectorAll)) && (ce(function(e) { (a.appendChild(e).innerHTML = ""), e.querySelectorAll("[msallowcapture^='']").length && v.push('[*^$]=' + M + '*(?:\'\'|"")'), e.querySelectorAll('[selected]').length || v.push('\\[' + M + '*(?:value|' + R + ')'), e.querySelectorAll('[id~=' + k + '-]').length || v.push('~='), e.querySelectorAll(':checked').length || v.push(':checked'), e.querySelectorAll('a#' + k + '+*').length || v.push('.#.+[+~]'); }), ce(function(e) { e.innerHTML = ""; var t = C.createElement('input'); t.setAttribute('type', 'hidden'), e.appendChild(t).setAttribute('name', 'D'), e.querySelectorAll('[name=d]').length && v.push('name' + M + '*[*^$|!~]?='), 2 !== e.querySelectorAll(':enabled').length && v.push(':enabled', ':disabled'), (a.appendChild(e).disabled = !0), 2 !== e.querySelectorAll(':disabled').length && v.push(':enabled', ':disabled'), e.querySelectorAll('*,:x'), v.push(',.*:'); })), (d.matchesSelector = K.test( (c = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.oMatchesSelector || a.msMatchesSelector), )) && ce(function(e) { (d.disconnectedMatch = c.call(e, '*')), c.call(e, "[s!='']:x"), s.push('!=', $); }), (v = v.length && new RegExp(v.join('|'))), (s = s.length && new RegExp(s.join('|'))), (t = K.test(a.compareDocumentPosition)), (y = t || K.test(a.contains) ? function(e, t) { var n = 9 === e.nodeType ? e.documentElement : e, r = t && t.parentNode; return ( e === r || !( !r || 1 !== r.nodeType || !(n.contains ? n.contains(r) : e.compareDocumentPosition && 16 & e.compareDocumentPosition(r)) ) ); } : function(e, t) { if (t) while ((t = t.parentNode)) if (t === e) return !0; return !1; }), (D = t ? function(e, t) { if (e === t) return (l = !0), 0; var n = !e.compareDocumentPosition - !t.compareDocumentPosition; return ( n || (1 & (n = (e.ownerDocument || e) === (t.ownerDocument || t) ? e.compareDocumentPosition(t) : 1) || (!d.sortDetached && t.compareDocumentPosition(e) === n) ? e === C || (e.ownerDocument === m && y(m, e)) ? -1 : t === C || (t.ownerDocument === m && y(m, t)) ? 1 : u ? P(u, e) - P(u, t) : 0 : 4 & n ? -1 : 1) ); } : function(e, t) { if (e === t) return (l = !0), 0; var n, r = 0, i = e.parentNode, o = t.parentNode, a = [e], s = [t]; if (!i || !o) return e === C ? -1 : t === C ? 1 : i ? -1 : o ? 1 : u ? P(u, e) - P(u, t) : 0; if (i === o) return pe(e, t); n = e; while ((n = n.parentNode)) a.unshift(n); n = t; while ((n = n.parentNode)) s.unshift(n); while (a[r] === s[r]) r++; return r ? pe(a[r], s[r]) : a[r] === m ? -1 : s[r] === m ? 1 : 0; })), C ); }), (se.matches = function(e, t) { return se(e, null, null, t); }), (se.matchesSelector = function(e, t) { if ( ((e.ownerDocument || e) !== C && T(e), d.matchesSelector && E && !A[t + ' '] && (!s || !s.test(t)) && (!v || !v.test(t))) ) try { var n = c.call(e, t); if (n || d.disconnectedMatch || (e.document && 11 !== e.document.nodeType)) return n; } catch (e) { A(t, !0); } return 0 < se(t, C, null, [e]).length; }), (se.contains = function(e, t) { return (e.ownerDocument || e) !== C && T(e), y(e, t); }), (se.attr = function(e, t) { (e.ownerDocument || e) !== C && T(e); var n = b.attrHandle[t.toLowerCase()], r = n && j.call(b.attrHandle, t.toLowerCase()) ? n(e, t, !E) : void 0; return void 0 !== r ? r : d.attributes || !E ? e.getAttribute(t) : (r = e.getAttributeNode(t)) && r.specified ? r.value : null; }), (se.escape = function(e) { return (e + '').replace(re, ie); }), (se.error = function(e) { throw new Error('Syntax error, unrecognized expression: ' + e); }), (se.uniqueSort = function(e) { var t, n = [], r = 0, i = 0; if (((l = !d.detectDuplicates), (u = !d.sortStable && e.slice(0)), e.sort(D), l)) { while ((t = e[i++])) t === e[i] && (r = n.push(i)); while (r--) e.splice(n[r], 1); } return (u = null), e; }), (o = se.getText = function(e) { var t, n = '', r = 0, i = e.nodeType; if (i) { if (1 === i || 9 === i || 11 === i) { if ('string' == typeof e.textContent) return e.textContent; for (e = e.firstChild; e; e = e.nextSibling) n += o(e); } else if (3 === i || 4 === i) return e.nodeValue; } else while ((t = e[r++])) n += o(t); return n; }), ((b = se.selectors = { cacheLength: 50, createPseudo: le, match: G, attrHandle: {}, find: {}, relative: { '>': { dir: 'parentNode', first: !0 }, ' ': { dir: 'parentNode' }, '+': { dir: 'previousSibling', first: !0 }, '~': { dir: 'previousSibling' }, }, preFilter: { ATTR: function(e) { return ( (e[1] = e[1].replace(te, ne)), (e[3] = (e[3] || e[4] || e[5] || '').replace(te, ne)), '~=' === e[2] && (e[3] = ' ' + e[3] + ' '), e.slice(0, 4) ); }, CHILD: function(e) { return ( (e[1] = e[1].toLowerCase()), 'nth' === e[1].slice(0, 3) ? (e[3] || se.error(e[0]), (e[4] = +(e[4] ? e[5] + (e[6] || 1) : 2 * ('even' === e[3] || 'odd' === e[3]))), (e[5] = +(e[7] + e[8] || 'odd' === e[3]))) : e[3] && se.error(e[0]), e ); }, PSEUDO: function(e) { var t, n = !e[6] && e[2]; return G.CHILD.test(e[0]) ? null : (e[3] ? (e[2] = e[4] || e[5] || '') : n && X.test(n) && (t = h(n, !0)) && (t = n.indexOf(')', n.length - t) - n.length) && ((e[0] = e[0].slice(0, t)), (e[2] = n.slice(0, t))), e.slice(0, 3)); }, }, filter: { TAG: function(e) { var t = e.replace(te, ne).toLowerCase(); return '*' === e ? function() { return !0; } : function(e) { return e.nodeName && e.nodeName.toLowerCase() === t; }; }, CLASS: function(e) { var t = p[e + ' ']; return ( t || ((t = new RegExp('(^|' + M + ')' + e + '(' + M + '|$)')) && p(e, function(e) { return t.test( ('string' == typeof e.className && e.className) || ('undefined' != typeof e.getAttribute && e.getAttribute('class')) || '', ); })) ); }, ATTR: function(n, r, i) { return function(e) { var t = se.attr(e, n); return null == t ? '!=' === r : !r || ((t += ''), '=' === r ? t === i : '!=' === r ? t !== i : '^=' === r ? i && 0 === t.indexOf(i) : '*=' === r ? i && -1 < t.indexOf(i) : '$=' === r ? i && t.slice(-i.length) === i : '~=' === r ? -1 < (' ' + t.replace(F, ' ') + ' ').indexOf(i) : '|=' === r && (t === i || t.slice(0, i.length + 1) === i + '-')); }; }, CHILD: function(h, e, t, g, v) { var y = 'nth' !== h.slice(0, 3), m = 'last' !== h.slice(-4), x = 'of-type' === e; return 1 === g && 0 === v ? function(e) { return !!e.parentNode; } : function(e, t, n) { var r, i, o, a, s, u, l = y !== m ? 'nextSibling' : 'previousSibling', c = e.parentNode, f = x && e.nodeName.toLowerCase(), p = !n && !x, d = !1; if (c) { if (y) { while (l) { a = e; while ((a = a[l])) if (x ? a.nodeName.toLowerCase() === f : 1 === a.nodeType) return !1; u = l = 'only' === h && !u && 'nextSibling'; } return !0; } if (((u = [m ? c.firstChild : c.lastChild]), m && p)) { (d = (s = (r = (i = (o = (a = c)[k] || (a[k] = {}))[a.uniqueID] || (o[a.uniqueID] = {}))[ h ] || [])[0] === S && r[1]) && r[2]), (a = s && c.childNodes[s]); while ((a = (++s && a && a[l]) || (d = s = 0) || u.pop())) if (1 === a.nodeType && ++d && a === e) { i[h] = [S, s, d]; break; } } else if ( (p && (d = s = (r = (i = (o = (a = e)[k] || (a[k] = {}))[a.uniqueID] || (o[a.uniqueID] = {}))[ h ] || [])[0] === S && r[1]), !1 === d) ) while ((a = (++s && a && a[l]) || (d = s = 0) || u.pop())) if ( (x ? a.nodeName.toLowerCase() === f : 1 === a.nodeType) && ++d && (p && ((i = (o = a[k] || (a[k] = {}))[a.uniqueID] || (o[a.uniqueID] = {}))[ h ] = [S, d]), a === e) ) break; return (d -= v) === g || (d % g == 0 && 0 <= d / g); } }; }, PSEUDO: function(e, o) { var t, a = b.pseudos[e] || b.setFilters[e.toLowerCase()] || se.error('unsupported pseudo: ' + e); return a[k] ? a(o) : 1 < a.length ? ((t = [e, e, '', o]), b.setFilters.hasOwnProperty(e.toLowerCase()) ? le(function(e, t) { var n, r = a(e, o), i = r.length; while (i--) e[(n = P(e, r[i]))] = !(t[n] = r[i]); }) : function(e) { return a(e, 0, t); }) : a; }, }, pseudos: { not: le(function(e) { var r = [], i = [], s = f(e.replace(B, '$1')); return s[k] ? le(function(e, t, n, r) { var i, o = s(e, null, r, []), a = e.length; while (a--) (i = o[a]) && (e[a] = !(t[a] = i)); }) : function(e, t, n) { return (r[0] = e), s(r, null, n, i), (r[0] = null), !i.pop(); }; }), has: le(function(t) { return function(e) { return 0 < se(t, e).length; }; }), contains: le(function(t) { return ( (t = t.replace(te, ne)), function(e) { return -1 < (e.textContent || o(e)).indexOf(t); } ); }), lang: le(function(n) { return ( V.test(n || '') || se.error('unsupported lang: ' + n), (n = n.replace(te, ne).toLowerCase()), function(e) { var t; do { if ((t = E ? e.lang : e.getAttribute('xml:lang') || e.getAttribute('lang'))) return (t = t.toLowerCase()) === n || 0 === t.indexOf(n + '-'); } while ((e = e.parentNode) && 1 === e.nodeType); return !1; } ); }), target: function(e) { var t = n.location && n.location.hash; return t && t.slice(1) === e.id; }, root: function(e) { return e === a; }, focus: function(e) { return ( e === C.activeElement && (!C.hasFocus || C.hasFocus()) && !!(e.type || e.href || ~e.tabIndex) ); }, enabled: ge(!1), disabled: ge(!0), checked: function(e) { var t = e.nodeName.toLowerCase(); return ('input' === t && !!e.checked) || ('option' === t && !!e.selected); }, selected: function(e) { return e.parentNode && e.parentNode.selectedIndex, !0 === e.selected; }, empty: function(e) { for (e = e.firstChild; e; e = e.nextSibling) if (e.nodeType < 6) return !1; return !0; }, parent: function(e) { return !b.pseudos.empty(e); }, header: function(e) { return J.test(e.nodeName); }, input: function(e) { return Q.test(e.nodeName); }, button: function(e) { var t = e.nodeName.toLowerCase(); return ('input' === t && 'button' === e.type) || 'button' === t; }, text: function(e) { var t; return ( 'input' === e.nodeName.toLowerCase() && 'text' === e.type && (null == (t = e.getAttribute('type')) || 'text' === t.toLowerCase()) ); }, first: ve(function() { return [0]; }), last: ve(function(e, t) { return [t - 1]; }), eq: ve(function(e, t, n) { return [n < 0 ? n + t : n]; }), even: ve(function(e, t) { for (var n = 0; n < t; n += 2) e.push(n); return e; }), odd: ve(function(e, t) { for (var n = 1; n < t; n += 2) e.push(n); return e; }), lt: ve(function(e, t, n) { for (var r = n < 0 ? n + t : t < n ? t : n; 0 <= --r; ) e.push(r); return e; }), gt: ve(function(e, t, n) { for (var r = n < 0 ? n + t : n; ++r < t; ) e.push(r); return e; }), }, }).pseudos.nth = b.pseudos.eq), { radio: !0, checkbox: !0, file: !0, password: !0, image: !0 })) b.pseudos[e] = de(e); for (e in { submit: !0, reset: !0 }) b.pseudos[e] = he(e); function me() {} function xe(e) { for (var t = 0, n = e.length, r = ''; t < n; t++) r += e[t].value; return r; } function be(s, e, t) { var u = e.dir, l = e.next, c = l || u, f = t && 'parentNode' === c, p = r++; return e.first ? function(e, t, n) { while ((e = e[u])) if (1 === e.nodeType || f) return s(e, t, n); return !1; } : function(e, t, n) { var r, i, o, a = [S, p]; if (n) { while ((e = e[u])) if ((1 === e.nodeType || f) && s(e, t, n)) return !0; } else while ((e = e[u])) if (1 === e.nodeType || f) if ( ((i = (o = e[k] || (e[k] = {}))[e.uniqueID] || (o[e.uniqueID] = {})), l && l === e.nodeName.toLowerCase()) ) e = e[u] || e; else { if ((r = i[c]) && r[0] === S && r[1] === p) return (a[2] = r[2]); if (((i[c] = a)[2] = s(e, t, n))) return !0; } return !1; }; } function we(i) { return 1 < i.length ? function(e, t, n) { var r = i.length; while (r--) if (!i[r](e, t, n)) return !1; return !0; } : i[0]; } function Te(e, t, n, r, i) { for (var o, a = [], s = 0, u = e.length, l = null != t; s < u; s++) (o = e[s]) && ((n && !n(o, r, i)) || (a.push(o), l && t.push(s))); return a; } function Ce(d, h, g, v, y, e) { return ( v && !v[k] && (v = Ce(v)), y && !y[k] && (y = Ce(y, e)), le(function(e, t, n, r) { var i, o, a, s = [], u = [], l = t.length, c = e || (function(e, t, n) { for (var r = 0, i = t.length; r < i; r++) se(e, t[r], n); return n; })(h || '*', n.nodeType ? [n] : n, []), f = !d || (!e && h) ? c : Te(c, s, d, n, r), p = g ? (y || (e ? d : l || v) ? [] : t) : f; if ((g && g(f, p, n, r), v)) { (i = Te(p, u)), v(i, [], n, r), (o = i.length); while (o--) (a = i[o]) && (p[u[o]] = !(f[u[o]] = a)); } if (e) { if (y || d) { if (y) { (i = []), (o = p.length); while (o--) (a = p[o]) && i.push((f[o] = a)); y(null, (p = []), i, r); } o = p.length; while (o--) (a = p[o]) && -1 < (i = y ? P(e, a) : s[o]) && (e[i] = !(t[i] = a)); } } else (p = Te(p === t ? p.splice(l, p.length) : p)), y ? y(null, t, p, r) : H.apply(t, p); }) ); } function Ee(e) { for ( var i, t, n, r = e.length, o = b.relative[e[0].type], a = o || b.relative[' '], s = o ? 1 : 0, u = be( function(e) { return e === i; }, a, !0, ), l = be( function(e) { return -1 < P(i, e); }, a, !0, ), c = [ function(e, t, n) { var r = (!o && (n || t !== w)) || ((i = t).nodeType ? u(e, t, n) : l(e, t, n)); return (i = null), r; }, ]; s < r; s++ ) if ((t = b.relative[e[s].type])) c = [be(we(c), t)]; else { if ((t = b.filter[e[s].type].apply(null, e[s].matches))[k]) { for (n = ++s; n < r; n++) if (b.relative[e[n].type]) break; return Ce( 1 < s && we(c), 1 < s && xe(e.slice(0, s - 1).concat({ value: ' ' === e[s - 2].type ? '*' : '' })).replace( B, '$1', ), t, s < n && Ee(e.slice(s, n)), n < r && Ee((e = e.slice(n))), n < r && xe(e), ); } c.push(t); } return we(c); } return ( (me.prototype = b.filters = b.pseudos), (b.setFilters = new me()), (h = se.tokenize = function(e, t) { var n, r, i, o, a, s, u, l = x[e + ' ']; if (l) return t ? 0 : l.slice(0); (a = e), (s = []), (u = b.preFilter); while (a) { for (o in ((n && !(r = _.exec(a))) || (r && (a = a.slice(r[0].length) || a), s.push((i = []))), (n = !1), (r = z.exec(a)) && ((n = r.shift()), i.push({ value: n, type: r[0].replace(B, ' ') }), (a = a.slice(n.length))), b.filter)) !(r = G[o].exec(a)) || (u[o] && !(r = u[o](r))) || ((n = r.shift()), i.push({ value: n, type: o, matches: r }), (a = a.slice(n.length))); if (!n) break; } return t ? a.length : a ? se.error(e) : x(e, s).slice(0); }), (f = se.compile = function(e, t) { var n, v, y, m, x, r, i = [], o = [], a = N[e + ' ']; if (!a) { t || (t = h(e)), (n = t.length); while (n--) (a = Ee(t[n]))[k] ? i.push(a) : o.push(a); (a = N( e, ((v = o), (m = 0 < (y = i).length), (x = 0 < v.length), (r = function(e, t, n, r, i) { var o, a, s, u = 0, l = '0', c = e && [], f = [], p = w, d = e || (x && b.find.TAG('*', i)), h = (S += null == p ? 1 : Math.random() || 0.1), g = d.length; for (i && (w = t === C || t || i); l !== g && null != (o = d[l]); l++) { if (x && o) { (a = 0), t || o.ownerDocument === C || (T(o), (n = !E)); while ((s = v[a++])) if (s(o, t || C, n)) { r.push(o); break; } i && (S = h); } m && ((o = !s && o) && u--, e && c.push(o)); } if (((u += l), m && l !== u)) { a = 0; while ((s = y[a++])) s(c, f, t, n); if (e) { if (0 < u) while (l--) c[l] || f[l] || (f[l] = q.call(r)); f = Te(f); } H.apply(r, f), i && !e && 0 < f.length && 1 < u + y.length && se.uniqueSort(r); } return i && ((S = h), (w = p)), c; }), m ? le(r) : r), )).selector = e; } return a; }), (g = se.select = function(e, t, n, r) { var i, o, a, s, u, l = 'function' == typeof e && e, c = !r && h((e = l.selector || e)); if (((n = n || []), 1 === c.length)) { if ( 2 < (o = c[0] = c[0].slice(0)).length && 'ID' === (a = o[0]).type && 9 === t.nodeType && E && b.relative[o[1].type] ) { if (!(t = (b.find.ID(a.matches[0].replace(te, ne), t) || [])[0])) return n; l && (t = t.parentNode), (e = e.slice(o.shift().value.length)); } i = G.needsContext.test(e) ? 0 : o.length; while (i--) { if (((a = o[i]), b.relative[(s = a.type)])) break; if ( (u = b.find[s]) && (r = u(a.matches[0].replace(te, ne), (ee.test(o[0].type) && ye(t.parentNode)) || t)) ) { if ((o.splice(i, 1), !(e = r.length && xe(o)))) return H.apply(n, r), n; break; } } } return (l || f(e, c))(r, t, !E, n, !t || (ee.test(e) && ye(t.parentNode)) || t), n; }), (d.sortStable = k .split('') .sort(D) .join('') === k), (d.detectDuplicates = !!l), T(), (d.sortDetached = ce(function(e) { return 1 & e.compareDocumentPosition(C.createElement('fieldset')); })), ce(function(e) { return (e.innerHTML = ""), '#' === e.firstChild.getAttribute('href'); }) || fe('type|href|height|width', function(e, t, n) { if (!n) return e.getAttribute(t, 'type' === t.toLowerCase() ? 1 : 2); }), (d.attributes && ce(function(e) { return ( (e.innerHTML = ''), e.firstChild.setAttribute('value', ''), '' === e.firstChild.getAttribute('value') ); })) || fe('value', function(e, t, n) { if (!n && 'input' === e.nodeName.toLowerCase()) return e.defaultValue; }), ce(function(e) { return null == e.getAttribute('disabled'); }) || fe(R, function(e, t, n) { var r; if (!n) return !0 === e[t] ? t.toLowerCase() : (r = e.getAttributeNode(t)) && r.specified ? r.value : null; }), se ); })(C); (k.find = h), (k.expr = h.selectors), (k.expr[':'] = k.expr.pseudos), (k.uniqueSort = k.unique = h.uniqueSort), (k.text = h.getText), (k.isXMLDoc = h.isXML), (k.contains = h.contains), (k.escapeSelector = h.escape); var T = function(e, t, n) { var r = [], i = void 0 !== n; while ((e = e[t]) && 9 !== e.nodeType) if (1 === e.nodeType) { if (i && k(e).is(n)) break; r.push(e); } return r; }, S = function(e, t) { for (var n = []; e; e = e.nextSibling) 1 === e.nodeType && e !== t && n.push(e); return n; }, N = k.expr.match.needsContext; function A(e, t) { return e.nodeName && e.nodeName.toLowerCase() === t.toLowerCase(); } var D = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i; function j(e, n, r) { return m(n) ? k.grep(e, function(e, t) { return !!n.call(e, t, e) !== r; }) : n.nodeType ? k.grep(e, function(e) { return (e === n) !== r; }) : 'string' != typeof n ? k.grep(e, function(e) { return -1 < i.call(n, e) !== r; }) : k.filter(n, e, r); } (k.filter = function(e, t, n) { var r = t[0]; return ( n && (e = ':not(' + e + ')'), 1 === t.length && 1 === r.nodeType ? k.find.matchesSelector(r, e) ? [r] : [] : k.find.matches( e, k.grep(t, function(e) { return 1 === e.nodeType; }), ) ); }), k.fn.extend({ find: function(e) { var t, n, r = this.length, i = this; if ('string' != typeof e) return this.pushStack( k(e).filter(function() { for (t = 0; t < r; t++) if (k.contains(i[t], this)) return !0; }), ); for (n = this.pushStack([]), t = 0; t < r; t++) k.find(e, i[t], n); return 1 < r ? k.uniqueSort(n) : n; }, filter: function(e) { return this.pushStack(j(this, e || [], !1)); }, not: function(e) { return this.pushStack(j(this, e || [], !0)); }, is: function(e) { return !!j(this, 'string' == typeof e && N.test(e) ? k(e) : e || [], !1).length; }, }); var q, L = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/; ((k.fn.init = function(e, t, n) { var r, i; if (!e) return this; if (((n = n || q), 'string' == typeof e)) { if ( !(r = '<' === e[0] && '>' === e[e.length - 1] && 3 <= e.length ? [null, e, null] : L.exec(e)) || (!r[1] && t) ) return !t || t.jquery ? (t || n).find(e) : this.constructor(t).find(e); if (r[1]) { if ( ((t = t instanceof k ? t[0] : t), k.merge(this, k.parseHTML(r[1], t && t.nodeType ? t.ownerDocument || t : E, !0)), D.test(r[1]) && k.isPlainObject(t)) ) for (r in t) m(this[r]) ? this[r](t[r]) : this.attr(r, t[r]); return this; } return (i = E.getElementById(r[2])) && ((this[0] = i), (this.length = 1)), this; } return e.nodeType ? ((this[0] = e), (this.length = 1), this) : m(e) ? void 0 !== n.ready ? n.ready(e) : e(k) : k.makeArray(e, this); }).prototype = k.fn), (q = k(E)); var H = /^(?:parents|prev(?:Until|All))/, O = { children: !0, contents: !0, next: !0, prev: !0 }; function P(e, t) { while ((e = e[t]) && 1 !== e.nodeType); return e; } k.fn.extend({ has: function(e) { var t = k(e, this), n = t.length; return this.filter(function() { for (var e = 0; e < n; e++) if (k.contains(this, t[e])) return !0; }); }, closest: function(e, t) { var n, r = 0, i = this.length, o = [], a = 'string' != typeof e && k(e); if (!N.test(e)) for (; r < i; r++) for (n = this[r]; n && n !== t; n = n.parentNode) if ( n.nodeType < 11 && (a ? -1 < a.index(n) : 1 === n.nodeType && k.find.matchesSelector(n, e)) ) { o.push(n); break; } return this.pushStack(1 < o.length ? k.uniqueSort(o) : o); }, index: function(e) { return e ? 'string' == typeof e ? i.call(k(e), this[0]) : i.call(this, e.jquery ? e[0] : e) : this[0] && this[0].parentNode ? this.first().prevAll().length : -1; }, add: function(e, t) { return this.pushStack(k.uniqueSort(k.merge(this.get(), k(e, t)))); }, addBack: function(e) { return this.add(null == e ? this.prevObject : this.prevObject.filter(e)); }, }), k.each( { parent: function(e) { var t = e.parentNode; return t && 11 !== t.nodeType ? t : null; }, parents: function(e) { return T(e, 'parentNode'); }, parentsUntil: function(e, t, n) { return T(e, 'parentNode', n); }, next: function(e) { return P(e, 'nextSibling'); }, prev: function(e) { return P(e, 'previousSibling'); }, nextAll: function(e) { return T(e, 'nextSibling'); }, prevAll: function(e) { return T(e, 'previousSibling'); }, nextUntil: function(e, t, n) { return T(e, 'nextSibling', n); }, prevUntil: function(e, t, n) { return T(e, 'previousSibling', n); }, siblings: function(e) { return S((e.parentNode || {}).firstChild, e); }, children: function(e) { return S(e.firstChild); }, contents: function(e) { return 'undefined' != typeof e.contentDocument ? e.contentDocument : (A(e, 'template') && (e = e.content || e), k.merge([], e.childNodes)); }, }, function(r, i) { k.fn[r] = function(e, t) { var n = k.map(this, i, e); return ( 'Until' !== r.slice(-5) && (t = e), t && 'string' == typeof t && (n = k.filter(t, n)), 1 < this.length && (O[r] || k.uniqueSort(n), H.test(r) && n.reverse()), this.pushStack(n) ); }; }, ); var R = /[^\x20\t\r\n\f]+/g; function M(e) { return e; } function I(e) { throw e; } function W(e, t, n, r) { var i; try { e && m((i = e.promise)) ? i .call(e) .done(t) .fail(n) : e && m((i = e.then)) ? i.call(e, t, n) : t.apply(void 0, [e].slice(r)); } catch (e) { n.apply(void 0, [e]); } } (k.Callbacks = function(r) { var e, n; r = 'string' == typeof r ? ((e = r), (n = {}), k.each(e.match(R) || [], function(e, t) { n[t] = !0; }), n) : k.extend({}, r); var i, t, o, a, s = [], u = [], l = -1, c = function() { for (a = a || r.once, o = i = !0; u.length; l = -1) { t = u.shift(); while (++l < s.length) !1 === s[l].apply(t[0], t[1]) && r.stopOnFalse && ((l = s.length), (t = !1)); } r.memory || (t = !1), (i = !1), a && (s = t ? [] : ''); }, f = { add: function() { return ( s && (t && !i && ((l = s.length - 1), u.push(t)), (function n(e) { k.each(e, function(e, t) { m(t) ? (r.unique && f.has(t)) || s.push(t) : t && t.length && 'string' !== w(t) && n(t); }); })(arguments), t && !i && c()), this ); }, remove: function() { return ( k.each(arguments, function(e, t) { var n; while (-1 < (n = k.inArray(t, s, n))) s.splice(n, 1), n <= l && l--; }), this ); }, has: function(e) { return e ? -1 < k.inArray(e, s) : 0 < s.length; }, empty: function() { return s && (s = []), this; }, disable: function() { return (a = u = []), (s = t = ''), this; }, disabled: function() { return !s; }, lock: function() { return (a = u = []), t || i || (s = t = ''), this; }, locked: function() { return !!a; }, fireWith: function(e, t) { return a || ((t = [e, (t = t || []).slice ? t.slice() : t]), u.push(t), i || c()), this; }, fire: function() { return f.fireWith(this, arguments), this; }, fired: function() { return !!o; }, }; return f; }), k.extend({ Deferred: function(e) { var o = [ ['notify', 'progress', k.Callbacks('memory'), k.Callbacks('memory'), 2], [ 'resolve', 'done', k.Callbacks('once memory'), k.Callbacks('once memory'), 0, 'resolved', ], [ 'reject', 'fail', k.Callbacks('once memory'), k.Callbacks('once memory'), 1, 'rejected', ], ], i = 'pending', a = { state: function() { return i; }, always: function() { return s.done(arguments).fail(arguments), this; }, catch: function(e) { return a.then(null, e); }, pipe: function() { var i = arguments; return k .Deferred(function(r) { k.each(o, function(e, t) { var n = m(i[t[4]]) && i[t[4]]; s[t[1]](function() { var e = n && n.apply(this, arguments); e && m(e.promise) ? e .promise() .progress(r.notify) .done(r.resolve) .fail(r.reject) : r[t[0] + 'With'](this, n ? [e] : arguments); }); }), (i = null); }) .promise(); }, then: function(t, n, r) { var u = 0; function l(i, o, a, s) { return function() { var n = this, r = arguments, e = function() { var e, t; if (!(i < u)) { if ((e = a.apply(n, r)) === o.promise()) throw new TypeError('Thenable self-resolution'); (t = e && ('object' == typeof e || 'function' == typeof e) && e.then), m(t) ? s ? t.call(e, l(u, o, M, s), l(u, o, I, s)) : (u++, t.call(e, l(u, o, M, s), l(u, o, I, s), l(u, o, M, o.notifyWith))) : (a !== M && ((n = void 0), (r = [e])), (s || o.resolveWith)(n, r)); } }, t = s ? e : function() { try { e(); } catch (e) { k.Deferred.exceptionHook && k.Deferred.exceptionHook(e, t.stackTrace), u <= i + 1 && (a !== I && ((n = void 0), (r = [e])), o.rejectWith(n, r)); } }; i ? t() : (k.Deferred.getStackHook && (t.stackTrace = k.Deferred.getStackHook()), C.setTimeout(t)); }; } return k .Deferred(function(e) { o[0][3].add(l(0, e, m(r) ? r : M, e.notifyWith)), o[1][3].add(l(0, e, m(t) ? t : M)), o[2][3].add(l(0, e, m(n) ? n : I)); }) .promise(); }, promise: function(e) { return null != e ? k.extend(e, a) : a; }, }, s = {}; return ( k.each(o, function(e, t) { var n = t[2], r = t[5]; (a[t[1]] = n.add), r && n.add( function() { i = r; }, o[3 - e][2].disable, o[3 - e][3].disable, o[0][2].lock, o[0][3].lock, ), n.add(t[3].fire), (s[t[0]] = function() { return s[t[0] + 'With'](this === s ? void 0 : this, arguments), this; }), (s[t[0] + 'With'] = n.fireWith); }), a.promise(s), e && e.call(s, s), s ); }, when: function(e) { var n = arguments.length, t = n, r = Array(t), i = s.call(arguments), o = k.Deferred(), a = function(t) { return function(e) { (r[t] = this), (i[t] = 1 < arguments.length ? s.call(arguments) : e), --n || o.resolveWith(r, i); }; }; if ( n <= 1 && (W(e, o.done(a(t)).resolve, o.reject, !n), 'pending' === o.state() || m(i[t] && i[t].then)) ) return o.then(); while (t--) W(i[t], a(t), o.reject); return o.promise(); }, }); var $ = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; (k.Deferred.exceptionHook = function(e, t) { C.console && C.console.warn && e && $.test(e.name) && C.console.warn('jQuery.Deferred exception: ' + e.message, e.stack, t); }), (k.readyException = function(e) { C.setTimeout(function() { throw e; }); }); var F = k.Deferred(); function B() { E.removeEventListener('DOMContentLoaded', B), C.removeEventListener('load', B), k.ready(); } (k.fn.ready = function(e) { return ( F.then(e)['catch'](function(e) { k.readyException(e); }), this ); }), k.extend({ isReady: !1, readyWait: 1, ready: function(e) { (!0 === e ? --k.readyWait : k.isReady) || ((k.isReady = !0) !== e && 0 < --k.readyWait) || F.resolveWith(E, [k]); }, }), (k.ready.then = F.then), 'complete' === E.readyState || ('loading' !== E.readyState && !E.documentElement.doScroll) ? C.setTimeout(k.ready) : (E.addEventListener('DOMContentLoaded', B), C.addEventListener('load', B)); var _ = function(e, t, n, r, i, o, a) { var s = 0, u = e.length, l = null == n; if ('object' === w(n)) for (s in ((i = !0), n)) _(e, t, s, n[s], !0, o, a); else if ( void 0 !== r && ((i = !0), m(r) || (a = !0), l && (a ? (t.call(e, r), (t = null)) : ((l = t), (t = function(e, t, n) { return l.call(k(e), n); }))), t) ) for (; s < u; s++) t(e[s], n, a ? r : r.call(e[s], s, t(e[s], n))); return i ? e : l ? t.call(e) : u ? t(e[0], n) : o; }, z = /^-ms-/, U = /-([a-z])/g; function X(e, t) { return t.toUpperCase(); } function V(e) { return e.replace(z, 'ms-').replace(U, X); } var G = function(e) { return 1 === e.nodeType || 9 === e.nodeType || !+e.nodeType; }; function Y() { this.expando = k.expando + Y.uid++; } (Y.uid = 1), (Y.prototype = { cache: function(e) { var t = e[this.expando]; return ( t || ((t = {}), G(e) && (e.nodeType ? (e[this.expando] = t) : Object.defineProperty(e, this.expando, { value: t, configurable: !0 }))), t ); }, set: function(e, t, n) { var r, i = this.cache(e); if ('string' == typeof t) i[V(t)] = n; else for (r in t) i[V(r)] = t[r]; return i; }, get: function(e, t) { return void 0 === t ? this.cache(e) : e[this.expando] && e[this.expando][V(t)]; }, access: function(e, t, n) { return void 0 === t || (t && 'string' == typeof t && void 0 === n) ? this.get(e, t) : (this.set(e, t, n), void 0 !== n ? n : t); }, remove: function(e, t) { var n, r = e[this.expando]; if (void 0 !== r) { if (void 0 !== t) { n = (t = Array.isArray(t) ? t.map(V) : (t = V(t)) in r ? [t] : t.match(R) || []).length; while (n--) delete r[t[n]]; } (void 0 === t || k.isEmptyObject(r)) && (e.nodeType ? (e[this.expando] = void 0) : delete e[this.expando]); } }, hasData: function(e) { var t = e[this.expando]; return void 0 !== t && !k.isEmptyObject(t); }, }); var Q = new Y(), J = new Y(), K = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, Z = /[A-Z]/g; function ee(e, t, n) { var r, i; if (void 0 === n && 1 === e.nodeType) if ( ((r = 'data-' + t.replace(Z, '-$&').toLowerCase()), 'string' == typeof (n = e.getAttribute(r))) ) { try { n = 'true' === (i = n) || ('false' !== i && ('null' === i ? null : i === +i + '' ? +i : K.test(i) ? JSON.parse(i) : i)); } catch (e) {} J.set(e, t, n); } else n = void 0; return n; } k.extend({ hasData: function(e) { return J.hasData(e) || Q.hasData(e); }, data: function(e, t, n) { return J.access(e, t, n); }, removeData: function(e, t) { J.remove(e, t); }, _data: function(e, t, n) { return Q.access(e, t, n); }, _removeData: function(e, t) { Q.remove(e, t); }, }), k.fn.extend({ data: function(n, e) { var t, r, i, o = this[0], a = o && o.attributes; if (void 0 === n) { if (this.length && ((i = J.get(o)), 1 === o.nodeType && !Q.get(o, 'hasDataAttrs'))) { t = a.length; while (t--) a[t] && 0 === (r = a[t].name).indexOf('data-') && ((r = V(r.slice(5))), ee(o, r, i[r])); Q.set(o, 'hasDataAttrs', !0); } return i; } return 'object' == typeof n ? this.each(function() { J.set(this, n); }) : _( this, function(e) { var t; if (o && void 0 === e) return void 0 !== (t = J.get(o, n)) ? t : void 0 !== (t = ee(o, n)) ? t : void 0; this.each(function() { J.set(this, n, e); }); }, null, e, 1 < arguments.length, null, !0, ); }, removeData: function(e) { return this.each(function() { J.remove(this, e); }); }, }), k.extend({ queue: function(e, t, n) { var r; if (e) return ( (t = (t || 'fx') + 'queue'), (r = Q.get(e, t)), n && (!r || Array.isArray(n) ? (r = Q.access(e, t, k.makeArray(n))) : r.push(n)), r || [] ); }, dequeue: function(e, t) { t = t || 'fx'; var n = k.queue(e, t), r = n.length, i = n.shift(), o = k._queueHooks(e, t); 'inprogress' === i && ((i = n.shift()), r--), i && ('fx' === t && n.unshift('inprogress'), delete o.stop, i.call( e, function() { k.dequeue(e, t); }, o, )), !r && o && o.empty.fire(); }, _queueHooks: function(e, t) { var n = t + 'queueHooks'; return ( Q.get(e, n) || Q.access(e, n, { empty: k.Callbacks('once memory').add(function() { Q.remove(e, [t + 'queue', n]); }), }) ); }, }), k.fn.extend({ queue: function(t, n) { var e = 2; return ( 'string' != typeof t && ((n = t), (t = 'fx'), e--), arguments.length < e ? k.queue(this[0], t) : void 0 === n ? this : this.each(function() { var e = k.queue(this, t, n); k._queueHooks(this, t), 'fx' === t && 'inprogress' !== e[0] && k.dequeue(this, t); }) ); }, dequeue: function(e) { return this.each(function() { k.dequeue(this, e); }); }, clearQueue: function(e) { return this.queue(e || 'fx', []); }, promise: function(e, t) { var n, r = 1, i = k.Deferred(), o = this, a = this.length, s = function() { --r || i.resolveWith(o, [o]); }; 'string' != typeof e && ((t = e), (e = void 0)), (e = e || 'fx'); while (a--) (n = Q.get(o[a], e + 'queueHooks')) && n.empty && (r++, n.empty.add(s)); return s(), i.promise(t); }, }); var te = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, ne = new RegExp('^(?:([+-])=|)(' + te + ')([a-z%]*)$', 'i'), re = ['Top', 'Right', 'Bottom', 'Left'], ie = E.documentElement, oe = function(e) { return k.contains(e.ownerDocument, e); }, ae = { composed: !0 }; ie.getRootNode && (oe = function(e) { return k.contains(e.ownerDocument, e) || e.getRootNode(ae) === e.ownerDocument; }); var se = function(e, t) { return ( 'none' === (e = t || e).style.display || ('' === e.style.display && oe(e) && 'none' === k.css(e, 'display')) ); }, ue = function(e, t, n, r) { var i, o, a = {}; for (o in t) (a[o] = e.style[o]), (e.style[o] = t[o]); for (o in ((i = n.apply(e, r || [])), t)) e.style[o] = a[o]; return i; }; function le(e, t, n, r) { var i, o, a = 20, s = r ? function() { return r.cur(); } : function() { return k.css(e, t, ''); }, u = s(), l = (n && n[3]) || (k.cssNumber[t] ? '' : 'px'), c = e.nodeType && (k.cssNumber[t] || ('px' !== l && +u)) && ne.exec(k.css(e, t)); if (c && c[3] !== l) { (u /= 2), (l = l || c[3]), (c = +u || 1); while (a--) k.style(e, t, c + l), (1 - o) * (1 - (o = s() / u || 0.5)) <= 0 && (a = 0), (c /= o); (c *= 2), k.style(e, t, c + l), (n = n || []); } return ( n && ((c = +c || +u || 0), (i = n[1] ? c + (n[1] + 1) * n[2] : +n[2]), r && ((r.unit = l), (r.start = c), (r.end = i))), i ); } var ce = {}; function fe(e, t) { for (var n, r, i, o, a, s, u, l = [], c = 0, f = e.length; c < f; c++) (r = e[c]).style && ((n = r.style.display), t ? ('none' === n && ((l[c] = Q.get(r, 'display') || null), l[c] || (r.style.display = '')), '' === r.style.display && se(r) && (l[c] = ((u = a = o = void 0), (a = (i = r).ownerDocument), (s = i.nodeName), (u = ce[s]) || ((o = a.body.appendChild(a.createElement(s))), (u = k.css(o, 'display')), o.parentNode.removeChild(o), 'none' === u && (u = 'block'), (ce[s] = u))))) : 'none' !== n && ((l[c] = 'none'), Q.set(r, 'display', n))); for (c = 0; c < f; c++) null != l[c] && (e[c].style.display = l[c]); return e; } k.fn.extend({ show: function() { return fe(this, !0); }, hide: function() { return fe(this); }, toggle: function(e) { return 'boolean' == typeof e ? e ? this.show() : this.hide() : this.each(function() { se(this) ? k(this).show() : k(this).hide(); }); }, }); var pe = /^(?:checkbox|radio)$/i, de = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i, he = /^$|^module$|\/(?:java|ecma)script/i, ge = { option: [1, "'], thead: [1, '
', '
'], col: [2, '', '
'], tr: [2, '', '
'], td: [3, '', '
'], _default: [0, '', ''], }; function ve(e, t) { var n; return ( (n = 'undefined' != typeof e.getElementsByTagName ? e.getElementsByTagName(t || '*') : 'undefined' != typeof e.querySelectorAll ? e.querySelectorAll(t || '*') : []), void 0 === t || (t && A(e, t)) ? k.merge([e], n) : n ); } function ye(e, t) { for (var n = 0, r = e.length; n < r; n++) Q.set(e[n], 'globalEval', !t || Q.get(t[n], 'globalEval')); } (ge.optgroup = ge.option), (ge.tbody = ge.tfoot = ge.colgroup = ge.caption = ge.thead), (ge.th = ge.td); var me, xe, be = /<|&#?\w+;/; function we(e, t, n, r, i) { for ( var o, a, s, u, l, c, f = t.createDocumentFragment(), p = [], d = 0, h = e.length; d < h; d++ ) if ((o = e[d]) || 0 === o) if ('object' === w(o)) k.merge(p, o.nodeType ? [o] : o); else if (be.test(o)) { (a = a || f.appendChild(t.createElement('div'))), (s = (de.exec(o) || ['', ''])[1].toLowerCase()), (u = ge[s] || ge._default), (a.innerHTML = u[1] + k.htmlPrefilter(o) + u[2]), (c = u[0]); while (c--) a = a.lastChild; k.merge(p, a.childNodes), ((a = f.firstChild).textContent = ''); } else p.push(t.createTextNode(o)); (f.textContent = ''), (d = 0); while ((o = p[d++])) if (r && -1 < k.inArray(o, r)) i && i.push(o); else if (((l = oe(o)), (a = ve(f.appendChild(o), 'script')), l && ye(a), n)) { c = 0; while ((o = a[c++])) he.test(o.type || '') && n.push(o); } return f; } (me = E.createDocumentFragment().appendChild(E.createElement('div'))), (xe = E.createElement('input')).setAttribute('type', 'radio'), xe.setAttribute('checked', 'checked'), xe.setAttribute('name', 't'), me.appendChild(xe), (y.checkClone = me.cloneNode(!0).cloneNode(!0).lastChild.checked), (me.innerHTML = ''), (y.noCloneChecked = !!me.cloneNode(!0).lastChild.defaultValue); var Te = /^key/, Ce = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, Ee = /^([^.]*)(?:\.(.+)|)/; function ke() { return !0; } function Se() { return !1; } function Ne(e, t) { return ( (e === (function() { try { return E.activeElement; } catch (e) {} })()) == ('focus' === t) ); } function Ae(e, t, n, r, i, o) { var a, s; if ('object' == typeof t) { for (s in ('string' != typeof n && ((r = r || n), (n = void 0)), t)) Ae(e, s, n, r, t[s], o); return e; } if ( (null == r && null == i ? ((i = n), (r = n = void 0)) : null == i && ('string' == typeof n ? ((i = r), (r = void 0)) : ((i = r), (r = n), (n = void 0))), !1 === i) ) i = Se; else if (!i) return e; return ( 1 === o && ((a = i), ((i = function(e) { return k().off(e), a.apply(this, arguments); }).guid = a.guid || (a.guid = k.guid++))), e.each(function() { k.event.add(this, t, i, r, n); }) ); } function De(e, i, o) { o ? (Q.set(e, i, !1), k.event.add(e, i, { namespace: !1, handler: function(e) { var t, n, r = Q.get(this, i); if (1 & e.isTrigger && this[i]) { if (r.length) (k.event.special[i] || {}).delegateType && e.stopPropagation(); else if ( ((r = s.call(arguments)), Q.set(this, i, r), (t = o(this, i)), this[i](), r !== (n = Q.get(this, i)) || t ? Q.set(this, i, !1) : (n = {}), r !== n) ) return e.stopImmediatePropagation(), e.preventDefault(), n.value; } else r.length && (Q.set(this, i, { value: k.event.trigger(k.extend(r[0], k.Event.prototype), r.slice(1), this), }), e.stopImmediatePropagation()); }, })) : void 0 === Q.get(e, i) && k.event.add(e, i, ke); } (k.event = { global: {}, add: function(t, e, n, r, i) { var o, a, s, u, l, c, f, p, d, h, g, v = Q.get(t); if (v) { n.handler && ((n = (o = n).handler), (i = o.selector)), i && k.find.matchesSelector(ie, i), n.guid || (n.guid = k.guid++), (u = v.events) || (u = v.events = {}), (a = v.handle) || (a = v.handle = function(e) { return 'undefined' != typeof k && k.event.triggered !== e.type ? k.event.dispatch.apply(t, arguments) : void 0; }), (l = (e = (e || '').match(R) || ['']).length); while (l--) (d = g = (s = Ee.exec(e[l]) || [])[1]), (h = (s[2] || '').split('.').sort()), d && ((f = k.event.special[d] || {}), (d = (i ? f.delegateType : f.bindType) || d), (f = k.event.special[d] || {}), (c = k.extend( { type: d, origType: g, data: r, handler: n, guid: n.guid, selector: i, needsContext: i && k.expr.match.needsContext.test(i), namespace: h.join('.'), }, o, )), (p = u[d]) || (((p = u[d] = []).delegateCount = 0), (f.setup && !1 !== f.setup.call(t, r, h, a)) || (t.addEventListener && t.addEventListener(d, a))), f.add && (f.add.call(t, c), c.handler.guid || (c.handler.guid = n.guid)), i ? p.splice(p.delegateCount++, 0, c) : p.push(c), (k.event.global[d] = !0)); } }, remove: function(e, t, n, r, i) { var o, a, s, u, l, c, f, p, d, h, g, v = Q.hasData(e) && Q.get(e); if (v && (u = v.events)) { l = (t = (t || '').match(R) || ['']).length; while (l--) if (((d = g = (s = Ee.exec(t[l]) || [])[1]), (h = (s[2] || '').split('.').sort()), d)) { (f = k.event.special[d] || {}), (p = u[(d = (r ? f.delegateType : f.bindType) || d)] || []), (s = s[2] && new RegExp('(^|\\.)' + h.join('\\.(?:.*\\.|)') + '(\\.|$)')), (a = o = p.length); while (o--) (c = p[o]), (!i && g !== c.origType) || (n && n.guid !== c.guid) || (s && !s.test(c.namespace)) || (r && r !== c.selector && ('**' !== r || !c.selector)) || (p.splice(o, 1), c.selector && p.delegateCount--, f.remove && f.remove.call(e, c)); a && !p.length && ((f.teardown && !1 !== f.teardown.call(e, h, v.handle)) || k.removeEvent(e, d, v.handle), delete u[d]); } else for (d in u) k.event.remove(e, d + t[l], n, r, !0); k.isEmptyObject(u) && Q.remove(e, 'handle events'); } }, dispatch: function(e) { var t, n, r, i, o, a, s = k.event.fix(e), u = new Array(arguments.length), l = (Q.get(this, 'events') || {})[s.type] || [], c = k.event.special[s.type] || {}; for (u[0] = s, t = 1; t < arguments.length; t++) u[t] = arguments[t]; if (((s.delegateTarget = this), !c.preDispatch || !1 !== c.preDispatch.call(this, s))) { (a = k.event.handlers.call(this, s, l)), (t = 0); while ((i = a[t++]) && !s.isPropagationStopped()) { (s.currentTarget = i.elem), (n = 0); while ((o = i.handlers[n++]) && !s.isImmediatePropagationStopped()) (s.rnamespace && !1 !== o.namespace && !s.rnamespace.test(o.namespace)) || ((s.handleObj = o), (s.data = o.data), void 0 !== (r = ((k.event.special[o.origType] || {}).handle || o.handler).apply(i.elem, u)) && !1 === (s.result = r) && (s.preventDefault(), s.stopPropagation())); } return c.postDispatch && c.postDispatch.call(this, s), s.result; } }, handlers: function(e, t) { var n, r, i, o, a, s = [], u = t.delegateCount, l = e.target; if (u && l.nodeType && !('click' === e.type && 1 <= e.button)) for (; l !== this; l = l.parentNode || this) if (1 === l.nodeType && ('click' !== e.type || !0 !== l.disabled)) { for (o = [], a = {}, n = 0; n < u; n++) void 0 === a[(i = (r = t[n]).selector + ' ')] && (a[i] = r.needsContext ? -1 < k(i, this).index(l) : k.find(i, this, null, [l]).length), a[i] && o.push(r); o.length && s.push({ elem: l, handlers: o }); } return (l = this), u < t.length && s.push({ elem: l, handlers: t.slice(u) }), s; }, addProp: function(t, e) { Object.defineProperty(k.Event.prototype, t, { enumerable: !0, configurable: !0, get: m(e) ? function() { if (this.originalEvent) return e(this.originalEvent); } : function() { if (this.originalEvent) return this.originalEvent[t]; }, set: function(e) { Object.defineProperty(this, t, { enumerable: !0, configurable: !0, writable: !0, value: e, }); }, }); }, fix: function(e) { return e[k.expando] ? e : new k.Event(e); }, special: { load: { noBubble: !0 }, click: { setup: function(e) { var t = this || e; return pe.test(t.type) && t.click && A(t, 'input') && De(t, 'click', ke), !1; }, trigger: function(e) { var t = this || e; return pe.test(t.type) && t.click && A(t, 'input') && De(t, 'click'), !0; }, _default: function(e) { var t = e.target; return (pe.test(t.type) && t.click && A(t, 'input') && Q.get(t, 'click')) || A(t, 'a'); }, }, beforeunload: { postDispatch: function(e) { void 0 !== e.result && e.originalEvent && (e.originalEvent.returnValue = e.result); }, }, }, }), (k.removeEvent = function(e, t, n) { e.removeEventListener && e.removeEventListener(t, n); }), (k.Event = function(e, t) { if (!(this instanceof k.Event)) return new k.Event(e, t); e && e.type ? ((this.originalEvent = e), (this.type = e.type), (this.isDefaultPrevented = e.defaultPrevented || (void 0 === e.defaultPrevented && !1 === e.returnValue) ? ke : Se), (this.target = e.target && 3 === e.target.nodeType ? e.target.parentNode : e.target), (this.currentTarget = e.currentTarget), (this.relatedTarget = e.relatedTarget)) : (this.type = e), t && k.extend(this, t), (this.timeStamp = (e && e.timeStamp) || Date.now()), (this[k.expando] = !0); }), (k.Event.prototype = { constructor: k.Event, isDefaultPrevented: Se, isPropagationStopped: Se, isImmediatePropagationStopped: Se, isSimulated: !1, preventDefault: function() { var e = this.originalEvent; (this.isDefaultPrevented = ke), e && !this.isSimulated && e.preventDefault(); }, stopPropagation: function() { var e = this.originalEvent; (this.isPropagationStopped = ke), e && !this.isSimulated && e.stopPropagation(); }, stopImmediatePropagation: function() { var e = this.originalEvent; (this.isImmediatePropagationStopped = ke), e && !this.isSimulated && e.stopImmediatePropagation(), this.stopPropagation(); }, }), k.each( { altKey: !0, bubbles: !0, cancelable: !0, changedTouches: !0, ctrlKey: !0, detail: !0, eventPhase: !0, metaKey: !0, pageX: !0, pageY: !0, shiftKey: !0, view: !0, char: !0, code: !0, charCode: !0, key: !0, keyCode: !0, button: !0, buttons: !0, clientX: !0, clientY: !0, offsetX: !0, offsetY: !0, pointerId: !0, pointerType: !0, screenX: !0, screenY: !0, targetTouches: !0, toElement: !0, touches: !0, which: function(e) { var t = e.button; return null == e.which && Te.test(e.type) ? null != e.charCode ? e.charCode : e.keyCode : !e.which && void 0 !== t && Ce.test(e.type) ? 1 & t ? 1 : 2 & t ? 3 : 4 & t ? 2 : 0 : e.which; }, }, k.event.addProp, ), k.each({ focus: 'focusin', blur: 'focusout' }, function(e, t) { k.event.special[e] = { setup: function() { return De(this, e, Ne), !1; }, trigger: function() { return De(this, e), !0; }, delegateType: t, }; }), k.each( { mouseenter: 'mouseover', mouseleave: 'mouseout', pointerenter: 'pointerover', pointerleave: 'pointerout', }, function(e, i) { k.event.special[e] = { delegateType: i, bindType: i, handle: function(e) { var t, n = e.relatedTarget, r = e.handleObj; return ( (n && (n === this || k.contains(this, n))) || ((e.type = r.origType), (t = r.handler.apply(this, arguments)), (e.type = i)), t ); }, }; }, ), k.fn.extend({ on: function(e, t, n, r) { return Ae(this, e, t, n, r); }, one: function(e, t, n, r) { return Ae(this, e, t, n, r, 1); }, off: function(e, t, n) { var r, i; if (e && e.preventDefault && e.handleObj) return ( (r = e.handleObj), k(e.delegateTarget).off( r.namespace ? r.origType + '.' + r.namespace : r.origType, r.selector, r.handler, ), this ); if ('object' == typeof e) { for (i in e) this.off(i, t, e[i]); return this; } return ( (!1 !== t && 'function' != typeof t) || ((n = t), (t = void 0)), !1 === n && (n = Se), this.each(function() { k.event.remove(this, e, n, t); }) ); }, }); var je = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, qe = /\s*$/g; function Oe(e, t) { return ( (A(e, 'table') && A(11 !== t.nodeType ? t : t.firstChild, 'tr') && k(e).children('tbody')[0]) || e ); } function Pe(e) { return (e.type = (null !== e.getAttribute('type')) + '/' + e.type), e; } function Re(e) { return ( 'true/' === (e.type || '').slice(0, 5) ? (e.type = e.type.slice(5)) : e.removeAttribute('type'), e ); } function Me(e, t) { var n, r, i, o, a, s, u, l; if (1 === t.nodeType) { if (Q.hasData(e) && ((o = Q.access(e)), (a = Q.set(t, o)), (l = o.events))) for (i in (delete a.handle, (a.events = {}), l)) for (n = 0, r = l[i].length; n < r; n++) k.event.add(t, i, l[i][n]); J.hasData(e) && ((s = J.access(e)), (u = k.extend({}, s)), J.set(t, u)); } } function Ie(n, r, i, o) { r = g.apply([], r); var e, t, a, s, u, l, c = 0, f = n.length, p = f - 1, d = r[0], h = m(d); if (h || (1 < f && 'string' == typeof d && !y.checkClone && Le.test(d))) return n.each(function(e) { var t = n.eq(e); h && (r[0] = d.call(this, e, t.html())), Ie(t, r, i, o); }); if ( f && ((t = (e = we(r, n[0].ownerDocument, !1, n, o)).firstChild), 1 === e.childNodes.length && (e = t), t || o) ) { for (s = (a = k.map(ve(e, 'script'), Pe)).length; c < f; c++) (u = e), c !== p && ((u = k.clone(u, !0, !0)), s && k.merge(a, ve(u, 'script'))), i.call(n[c], u, c); if (s) for (l = a[a.length - 1].ownerDocument, k.map(a, Re), c = 0; c < s; c++) (u = a[c]), he.test(u.type || '') && !Q.access(u, 'globalEval') && k.contains(l, u) && (u.src && 'module' !== (u.type || '').toLowerCase() ? k._evalUrl && !u.noModule && k._evalUrl(u.src, { nonce: u.nonce || u.getAttribute('nonce') }) : b(u.textContent.replace(He, ''), u, l)); } return n; } function We(e, t, n) { for (var r, i = t ? k.filter(t, e) : e, o = 0; null != (r = i[o]); o++) n || 1 !== r.nodeType || k.cleanData(ve(r)), r.parentNode && (n && oe(r) && ye(ve(r, 'script')), r.parentNode.removeChild(r)); return e; } k.extend({ htmlPrefilter: function(e) { return e.replace(je, '<$1>'); }, clone: function(e, t, n) { var r, i, o, a, s, u, l, c = e.cloneNode(!0), f = oe(e); if (!(y.noCloneChecked || (1 !== e.nodeType && 11 !== e.nodeType) || k.isXMLDoc(e))) for (a = ve(c), r = 0, i = (o = ve(e)).length; r < i; r++) (s = o[r]), (u = a[r]), void 0, 'input' === (l = u.nodeName.toLowerCase()) && pe.test(s.type) ? (u.checked = s.checked) : ('input' !== l && 'textarea' !== l) || (u.defaultValue = s.defaultValue); if (t) if (n) for (o = o || ve(e), a = a || ve(c), r = 0, i = o.length; r < i; r++) Me(o[r], a[r]); else Me(e, c); return 0 < (a = ve(c, 'script')).length && ye(a, !f && ve(e, 'script')), c; }, cleanData: function(e) { for (var t, n, r, i = k.event.special, o = 0; void 0 !== (n = e[o]); o++) if (G(n)) { if ((t = n[Q.expando])) { if (t.events) for (r in t.events) i[r] ? k.event.remove(n, r) : k.removeEvent(n, r, t.handle); n[Q.expando] = void 0; } n[J.expando] && (n[J.expando] = void 0); } }, }), k.fn.extend({ detach: function(e) { return We(this, e, !0); }, remove: function(e) { return We(this, e); }, text: function(e) { return _( this, function(e) { return void 0 === e ? k.text(this) : this.empty().each(function() { (1 !== this.nodeType && 11 !== this.nodeType && 9 !== this.nodeType) || (this.textContent = e); }); }, null, e, arguments.length, ); }, append: function() { return Ie(this, arguments, function(e) { (1 !== this.nodeType && 11 !== this.nodeType && 9 !== this.nodeType) || Oe(this, e).appendChild(e); }); }, prepend: function() { return Ie(this, arguments, function(e) { if (1 === this.nodeType || 11 === this.nodeType || 9 === this.nodeType) { var t = Oe(this, e); t.insertBefore(e, t.firstChild); } }); }, before: function() { return Ie(this, arguments, function(e) { this.parentNode && this.parentNode.insertBefore(e, this); }); }, after: function() { return Ie(this, arguments, function(e) { this.parentNode && this.parentNode.insertBefore(e, this.nextSibling); }); }, empty: function() { for (var e, t = 0; null != (e = this[t]); t++) 1 === e.nodeType && (k.cleanData(ve(e, !1)), (e.textContent = '')); return this; }, clone: function(e, t) { return ( (e = null != e && e), (t = null == t ? e : t), this.map(function() { return k.clone(this, e, t); }) ); }, html: function(e) { return _( this, function(e) { var t = this[0] || {}, n = 0, r = this.length; if (void 0 === e && 1 === t.nodeType) return t.innerHTML; if ( 'string' == typeof e && !qe.test(e) && !ge[(de.exec(e) || ['', ''])[1].toLowerCase()] ) { e = k.htmlPrefilter(e); try { for (; n < r; n++) 1 === (t = this[n] || {}).nodeType && (k.cleanData(ve(t, !1)), (t.innerHTML = e)); t = 0; } catch (e) {} } t && this.empty().append(e); }, null, e, arguments.length, ); }, replaceWith: function() { var n = []; return Ie( this, arguments, function(e) { var t = this.parentNode; k.inArray(this, n) < 0 && (k.cleanData(ve(this)), t && t.replaceChild(e, this)); }, n, ); }, }), k.each( { appendTo: 'append', prependTo: 'prepend', insertBefore: 'before', insertAfter: 'after', replaceAll: 'replaceWith', }, function(e, a) { k.fn[e] = function(e) { for (var t, n = [], r = k(e), i = r.length - 1, o = 0; o <= i; o++) (t = o === i ? this : this.clone(!0)), k(r[o])[a](t), u.apply(n, t.get()); return this.pushStack(n); }; }, ); var $e = new RegExp('^(' + te + ')(?!px)[a-z%]+$', 'i'), Fe = function(e) { var t = e.ownerDocument.defaultView; return (t && t.opener) || (t = C), t.getComputedStyle(e); }, Be = new RegExp(re.join('|'), 'i'); function _e(e, t, n) { var r, i, o, a, s = e.style; return ( (n = n || Fe(e)) && ('' !== (a = n.getPropertyValue(t) || n[t]) || oe(e) || (a = k.style(e, t)), !y.pixelBoxStyles() && $e.test(a) && Be.test(t) && ((r = s.width), (i = s.minWidth), (o = s.maxWidth), (s.minWidth = s.maxWidth = s.width = a), (a = n.width), (s.width = r), (s.minWidth = i), (s.maxWidth = o))), void 0 !== a ? a + '' : a ); } function ze(e, t) { return { get: function() { if (!e()) return (this.get = t).apply(this, arguments); delete this.get; }, }; } !(function() { function e() { if (u) { (s.style.cssText = 'position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0'), (u.style.cssText = 'position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%'), ie.appendChild(s).appendChild(u); var e = C.getComputedStyle(u); (n = '1%' !== e.top), (a = 12 === t(e.marginLeft)), (u.style.right = '60%'), (o = 36 === t(e.right)), (r = 36 === t(e.width)), (u.style.position = 'absolute'), (i = 12 === t(u.offsetWidth / 3)), ie.removeChild(s), (u = null); } } function t(e) { return Math.round(parseFloat(e)); } var n, r, i, o, a, s = E.createElement('div'), u = E.createElement('div'); u.style && ((u.style.backgroundClip = 'content-box'), (u.cloneNode(!0).style.backgroundClip = ''), (y.clearCloneStyle = 'content-box' === u.style.backgroundClip), k.extend(y, { boxSizingReliable: function() { return e(), r; }, pixelBoxStyles: function() { return e(), o; }, pixelPosition: function() { return e(), n; }, reliableMarginLeft: function() { return e(), a; }, scrollboxSize: function() { return e(), i; }, })); })(); var Ue = ['Webkit', 'Moz', 'ms'], Xe = E.createElement('div').style, Ve = {}; function Ge(e) { var t = k.cssProps[e] || Ve[e]; return ( t || (e in Xe ? e : (Ve[e] = (function(e) { var t = e[0].toUpperCase() + e.slice(1), n = Ue.length; while (n--) if ((e = Ue[n] + t) in Xe) return e; })(e) || e)) ); } var Ye = /^(none|table(?!-c[ea]).+)/, Qe = /^--/, Je = { position: 'absolute', visibility: 'hidden', display: 'block' }, Ke = { letterSpacing: '0', fontWeight: '400' }; function Ze(e, t, n) { var r = ne.exec(t); return r ? Math.max(0, r[2] - (n || 0)) + (r[3] || 'px') : t; } function et(e, t, n, r, i, o) { var a = 'width' === t ? 1 : 0, s = 0, u = 0; if (n === (r ? 'border' : 'content')) return 0; for (; a < 4; a += 2) 'margin' === n && (u += k.css(e, n + re[a], !0, i)), r ? ('content' === n && (u -= k.css(e, 'padding' + re[a], !0, i)), 'margin' !== n && (u -= k.css(e, 'border' + re[a] + 'Width', !0, i))) : ((u += k.css(e, 'padding' + re[a], !0, i)), 'padding' !== n ? (u += k.css(e, 'border' + re[a] + 'Width', !0, i)) : (s += k.css(e, 'border' + re[a] + 'Width', !0, i))); return ( !r && 0 <= o && (u += Math.max(0, Math.ceil(e['offset' + t[0].toUpperCase() + t.slice(1)] - o - u - s - 0.5)) || 0), u ); } function tt(e, t, n) { var r = Fe(e), i = (!y.boxSizingReliable() || n) && 'border-box' === k.css(e, 'boxSizing', !1, r), o = i, a = _e(e, t, r), s = 'offset' + t[0].toUpperCase() + t.slice(1); if ($e.test(a)) { if (!n) return a; a = 'auto'; } return ( ((!y.boxSizingReliable() && i) || 'auto' === a || (!parseFloat(a) && 'inline' === k.css(e, 'display', !1, r))) && e.getClientRects().length && ((i = 'border-box' === k.css(e, 'boxSizing', !1, r)), (o = s in e) && (a = e[s])), (a = parseFloat(a) || 0) + et(e, t, n || (i ? 'border' : 'content'), o, r, a) + 'px' ); } function nt(e, t, n, r, i) { return new nt.prototype.init(e, t, n, r, i); } k.extend({ cssHooks: { opacity: { get: function(e, t) { if (t) { var n = _e(e, 'opacity'); return '' === n ? '1' : n; } }, }, }, cssNumber: { animationIterationCount: !0, columnCount: !0, fillOpacity: !0, flexGrow: !0, flexShrink: !0, fontWeight: !0, gridArea: !0, gridColumn: !0, gridColumnEnd: !0, gridColumnStart: !0, gridRow: !0, gridRowEnd: !0, gridRowStart: !0, lineHeight: !0, opacity: !0, order: !0, orphans: !0, widows: !0, zIndex: !0, zoom: !0, }, cssProps: {}, style: function(e, t, n, r) { if (e && 3 !== e.nodeType && 8 !== e.nodeType && e.style) { var i, o, a, s = V(t), u = Qe.test(t), l = e.style; if ((u || (t = Ge(s)), (a = k.cssHooks[t] || k.cssHooks[s]), void 0 === n)) return a && 'get' in a && void 0 !== (i = a.get(e, !1, r)) ? i : l[t]; 'string' === (o = typeof n) && (i = ne.exec(n)) && i[1] && ((n = le(e, t, i)), (o = 'number')), null != n && n == n && ('number' !== o || u || (n += (i && i[3]) || (k.cssNumber[s] ? '' : 'px')), y.clearCloneStyle || '' !== n || 0 !== t.indexOf('background') || (l[t] = 'inherit'), (a && 'set' in a && void 0 === (n = a.set(e, n, r))) || (u ? l.setProperty(t, n) : (l[t] = n))); } }, css: function(e, t, n, r) { var i, o, a, s = V(t); return ( Qe.test(t) || (t = Ge(s)), (a = k.cssHooks[t] || k.cssHooks[s]) && 'get' in a && (i = a.get(e, !0, n)), void 0 === i && (i = _e(e, t, r)), 'normal' === i && t in Ke && (i = Ke[t]), '' === n || n ? ((o = parseFloat(i)), !0 === n || isFinite(o) ? o || 0 : i) : i ); }, }), k.each(['height', 'width'], function(e, u) { k.cssHooks[u] = { get: function(e, t, n) { if (t) return !Ye.test(k.css(e, 'display')) || (e.getClientRects().length && e.getBoundingClientRect().width) ? tt(e, u, n) : ue(e, Je, function() { return tt(e, u, n); }); }, set: function(e, t, n) { var r, i = Fe(e), o = !y.scrollboxSize() && 'absolute' === i.position, a = (o || n) && 'border-box' === k.css(e, 'boxSizing', !1, i), s = n ? et(e, u, n, a, i) : 0; return ( a && o && (s -= Math.ceil( e['offset' + u[0].toUpperCase() + u.slice(1)] - parseFloat(i[u]) - et(e, u, 'border', !1, i) - 0.5, )), s && (r = ne.exec(t)) && 'px' !== (r[3] || 'px') && ((e.style[u] = t), (t = k.css(e, u))), Ze(0, t, s) ); }, }; }), (k.cssHooks.marginLeft = ze(y.reliableMarginLeft, function(e, t) { if (t) return ( (parseFloat(_e(e, 'marginLeft')) || e.getBoundingClientRect().left - ue(e, { marginLeft: 0 }, function() { return e.getBoundingClientRect().left; })) + 'px' ); })), k.each({ margin: '', padding: '', border: 'Width' }, function(i, o) { (k.cssHooks[i + o] = { expand: function(e) { for (var t = 0, n = {}, r = 'string' == typeof e ? e.split(' ') : [e]; t < 4; t++) n[i + re[t] + o] = r[t] || r[t - 2] || r[0]; return n; }, }), 'margin' !== i && (k.cssHooks[i + o].set = Ze); }), k.fn.extend({ css: function(e, t) { return _( this, function(e, t, n) { var r, i, o = {}, a = 0; if (Array.isArray(t)) { for (r = Fe(e), i = t.length; a < i; a++) o[t[a]] = k.css(e, t[a], !1, r); return o; } return void 0 !== n ? k.style(e, t, n) : k.css(e, t); }, e, t, 1 < arguments.length, ); }, }), (((k.Tween = nt).prototype = { constructor: nt, init: function(e, t, n, r, i, o) { (this.elem = e), (this.prop = n), (this.easing = i || k.easing._default), (this.options = t), (this.start = this.now = this.cur()), (this.end = r), (this.unit = o || (k.cssNumber[n] ? '' : 'px')); }, cur: function() { var e = nt.propHooks[this.prop]; return e && e.get ? e.get(this) : nt.propHooks._default.get(this); }, run: function(e) { var t, n = nt.propHooks[this.prop]; return ( this.options.duration ? (this.pos = t = k.easing[this.easing]( e, this.options.duration * e, 0, 1, this.options.duration, )) : (this.pos = t = e), (this.now = (this.end - this.start) * t + this.start), this.options.step && this.options.step.call(this.elem, this.now, this), n && n.set ? n.set(this) : nt.propHooks._default.set(this), this ); }, }).init.prototype = nt.prototype), ((nt.propHooks = { _default: { get: function(e) { var t; return 1 !== e.elem.nodeType || (null != e.elem[e.prop] && null == e.elem.style[e.prop]) ? e.elem[e.prop] : (t = k.css(e.elem, e.prop, '')) && 'auto' !== t ? t : 0; }, set: function(e) { k.fx.step[e.prop] ? k.fx.step[e.prop](e) : 1 !== e.elem.nodeType || (!k.cssHooks[e.prop] && null == e.elem.style[Ge(e.prop)]) ? (e.elem[e.prop] = e.now) : k.style(e.elem, e.prop, e.now + e.unit); }, }, }).scrollTop = nt.propHooks.scrollLeft = { set: function(e) { e.elem.nodeType && e.elem.parentNode && (e.elem[e.prop] = e.now); }, }), (k.easing = { linear: function(e) { return e; }, swing: function(e) { return 0.5 - Math.cos(e * Math.PI) / 2; }, _default: 'swing', }), (k.fx = nt.prototype.init), (k.fx.step = {}); var rt, it, ot, at, st = /^(?:toggle|show|hide)$/, ut = /queueHooks$/; function lt() { it && (!1 === E.hidden && C.requestAnimationFrame ? C.requestAnimationFrame(lt) : C.setTimeout(lt, k.fx.interval), k.fx.tick()); } function ct() { return ( C.setTimeout(function() { rt = void 0; }), (rt = Date.now()) ); } function ft(e, t) { var n, r = 0, i = { height: e }; for (t = t ? 1 : 0; r < 4; r += 2 - t) i['margin' + (n = re[r])] = i['padding' + n] = e; return t && (i.opacity = i.width = e), i; } function pt(e, t, n) { for ( var r, i = (dt.tweeners[t] || []).concat(dt.tweeners['*']), o = 0, a = i.length; o < a; o++ ) if ((r = i[o].call(n, t, e))) return r; } function dt(o, e, t) { var n, a, r = 0, i = dt.prefilters.length, s = k.Deferred().always(function() { delete u.elem; }), u = function() { if (a) return !1; for ( var e = rt || ct(), t = Math.max(0, l.startTime + l.duration - e), n = 1 - (t / l.duration || 0), r = 0, i = l.tweens.length; r < i; r++ ) l.tweens[r].run(n); return ( s.notifyWith(o, [l, n, t]), n < 1 && i ? t : (i || s.notifyWith(o, [l, 1, 0]), s.resolveWith(o, [l]), !1) ); }, l = s.promise({ elem: o, props: k.extend({}, e), opts: k.extend(!0, { specialEasing: {}, easing: k.easing._default }, t), originalProperties: e, originalOptions: t, startTime: rt || ct(), duration: t.duration, tweens: [], createTween: function(e, t) { var n = k.Tween(o, l.opts, e, t, l.opts.specialEasing[e] || l.opts.easing); return l.tweens.push(n), n; }, stop: function(e) { var t = 0, n = e ? l.tweens.length : 0; if (a) return this; for (a = !0; t < n; t++) l.tweens[t].run(1); return ( e ? (s.notifyWith(o, [l, 1, 0]), s.resolveWith(o, [l, e])) : s.rejectWith(o, [l, e]), this ); }, }), c = l.props; for ( !(function(e, t) { var n, r, i, o, a; for (n in e) if ( ((i = t[(r = V(n))]), (o = e[n]), Array.isArray(o) && ((i = o[1]), (o = e[n] = o[0])), n !== r && ((e[r] = o), delete e[n]), (a = k.cssHooks[r]) && ('expand' in a)) ) for (n in ((o = a.expand(o)), delete e[r], o)) (n in e) || ((e[n] = o[n]), (t[n] = i)); else t[r] = i; })(c, l.opts.specialEasing); r < i; r++ ) if ((n = dt.prefilters[r].call(l, o, c, l.opts))) return m(n.stop) && (k._queueHooks(l.elem, l.opts.queue).stop = n.stop.bind(n)), n; return ( k.map(c, pt, l), m(l.opts.start) && l.opts.start.call(o, l), l .progress(l.opts.progress) .done(l.opts.done, l.opts.complete) .fail(l.opts.fail) .always(l.opts.always), k.fx.timer(k.extend(u, { elem: o, anim: l, queue: l.opts.queue })), l ); } (k.Animation = k.extend(dt, { tweeners: { '*': [ function(e, t) { var n = this.createTween(e, t); return le(n.elem, e, ne.exec(t), n), n; }, ], }, tweener: function(e, t) { m(e) ? ((t = e), (e = ['*'])) : (e = e.match(R)); for (var n, r = 0, i = e.length; r < i; r++) (n = e[r]), (dt.tweeners[n] = dt.tweeners[n] || []), dt.tweeners[n].unshift(t); }, prefilters: [ function(e, t, n) { var r, i, o, a, s, u, l, c, f = 'width' in t || 'height' in t, p = this, d = {}, h = e.style, g = e.nodeType && se(e), v = Q.get(e, 'fxshow'); for (r in (n.queue || (null == (a = k._queueHooks(e, 'fx')).unqueued && ((a.unqueued = 0), (s = a.empty.fire), (a.empty.fire = function() { a.unqueued || s(); })), a.unqueued++, p.always(function() { p.always(function() { a.unqueued--, k.queue(e, 'fx').length || a.empty.fire(); }); })), t)) if (((i = t[r]), st.test(i))) { if ((delete t[r], (o = o || 'toggle' === i), i === (g ? 'hide' : 'show'))) { if ('show' !== i || !v || void 0 === v[r]) continue; g = !0; } d[r] = (v && v[r]) || k.style(e, r); } if ((u = !k.isEmptyObject(t)) || !k.isEmptyObject(d)) for (r in (f && 1 === e.nodeType && ((n.overflow = [h.overflow, h.overflowX, h.overflowY]), null == (l = v && v.display) && (l = Q.get(e, 'display')), 'none' === (c = k.css(e, 'display')) && (l ? (c = l) : (fe([e], !0), (l = e.style.display || l), (c = k.css(e, 'display')), fe([e]))), ('inline' === c || ('inline-block' === c && null != l)) && 'none' === k.css(e, 'float') && (u || (p.done(function() { h.display = l; }), null == l && ((c = h.display), (l = 'none' === c ? '' : c))), (h.display = 'inline-block'))), n.overflow && ((h.overflow = 'hidden'), p.always(function() { (h.overflow = n.overflow[0]), (h.overflowX = n.overflow[1]), (h.overflowY = n.overflow[2]); })), (u = !1), d)) u || (v ? 'hidden' in v && (g = v.hidden) : (v = Q.access(e, 'fxshow', { display: l })), o && (v.hidden = !g), g && fe([e], !0), p.done(function() { for (r in (g || fe([e]), Q.remove(e, 'fxshow'), d)) k.style(e, r, d[r]); })), (u = pt(g ? v[r] : 0, r, p)), r in v || ((v[r] = u.start), g && ((u.end = u.start), (u.start = 0))); }, ], prefilter: function(e, t) { t ? dt.prefilters.unshift(e) : dt.prefilters.push(e); }, })), (k.speed = function(e, t, n) { var r = e && 'object' == typeof e ? k.extend({}, e) : { complete: n || (!n && t) || (m(e) && e), duration: e, easing: (n && t) || (t && !m(t) && t), }; return ( k.fx.off ? (r.duration = 0) : 'number' != typeof r.duration && (r.duration in k.fx.speeds ? (r.duration = k.fx.speeds[r.duration]) : (r.duration = k.fx.speeds._default)), (null != r.queue && !0 !== r.queue) || (r.queue = 'fx'), (r.old = r.complete), (r.complete = function() { m(r.old) && r.old.call(this), r.queue && k.dequeue(this, r.queue); }), r ); }), k.fn.extend({ fadeTo: function(e, t, n, r) { return this.filter(se) .css('opacity', 0) .show() .end() .animate({ opacity: t }, e, n, r); }, animate: function(t, e, n, r) { var i = k.isEmptyObject(t), o = k.speed(e, n, r), a = function() { var e = dt(this, k.extend({}, t), o); (i || Q.get(this, 'finish')) && e.stop(!0); }; return (a.finish = a), i || !1 === o.queue ? this.each(a) : this.queue(o.queue, a); }, stop: function(i, e, o) { var a = function(e) { var t = e.stop; delete e.stop, t(o); }; return ( 'string' != typeof i && ((o = e), (e = i), (i = void 0)), e && !1 !== i && this.queue(i || 'fx', []), this.each(function() { var e = !0, t = null != i && i + 'queueHooks', n = k.timers, r = Q.get(this); if (t) r[t] && r[t].stop && a(r[t]); else for (t in r) r[t] && r[t].stop && ut.test(t) && a(r[t]); for (t = n.length; t--; ) n[t].elem !== this || (null != i && n[t].queue !== i) || (n[t].anim.stop(o), (e = !1), n.splice(t, 1)); (!e && o) || k.dequeue(this, i); }) ); }, finish: function(a) { return ( !1 !== a && (a = a || 'fx'), this.each(function() { var e, t = Q.get(this), n = t[a + 'queue'], r = t[a + 'queueHooks'], i = k.timers, o = n ? n.length : 0; for ( t.finish = !0, k.queue(this, a, []), r && r.stop && r.stop.call(this, !0), e = i.length; e--; ) i[e].elem === this && i[e].queue === a && (i[e].anim.stop(!0), i.splice(e, 1)); for (e = 0; e < o; e++) n[e] && n[e].finish && n[e].finish.call(this); delete t.finish; }) ); }, }), k.each(['toggle', 'show', 'hide'], function(e, r) { var i = k.fn[r]; k.fn[r] = function(e, t, n) { return null == e || 'boolean' == typeof e ? i.apply(this, arguments) : this.animate(ft(r, !0), e, t, n); }; }), k.each( { slideDown: ft('show'), slideUp: ft('hide'), slideToggle: ft('toggle'), fadeIn: { opacity: 'show' }, fadeOut: { opacity: 'hide' }, fadeToggle: { opacity: 'toggle' }, }, function(e, r) { k.fn[e] = function(e, t, n) { return this.animate(r, e, t, n); }; }, ), (k.timers = []), (k.fx.tick = function() { var e, t = 0, n = k.timers; for (rt = Date.now(); t < n.length; t++) (e = n[t])() || n[t] !== e || n.splice(t--, 1); n.length || k.fx.stop(), (rt = void 0); }), (k.fx.timer = function(e) { k.timers.push(e), k.fx.start(); }), (k.fx.interval = 13), (k.fx.start = function() { it || ((it = !0), lt()); }), (k.fx.stop = function() { it = null; }), (k.fx.speeds = { slow: 600, fast: 200, _default: 400 }), (k.fn.delay = function(r, e) { return ( (r = (k.fx && k.fx.speeds[r]) || r), (e = e || 'fx'), this.queue(e, function(e, t) { var n = C.setTimeout(e, r); t.stop = function() { C.clearTimeout(n); }; }) ); }), (ot = E.createElement('input')), (at = E.createElement('select').appendChild(E.createElement('option'))), (ot.type = 'checkbox'), (y.checkOn = '' !== ot.value), (y.optSelected = at.selected), ((ot = E.createElement('input')).value = 't'), (ot.type = 'radio'), (y.radioValue = 't' === ot.value); var ht, gt = k.expr.attrHandle; k.fn.extend({ attr: function(e, t) { return _(this, k.attr, e, t, 1 < arguments.length); }, removeAttr: function(e) { return this.each(function() { k.removeAttr(this, e); }); }, }), k.extend({ attr: function(e, t, n) { var r, i, o = e.nodeType; if (3 !== o && 8 !== o && 2 !== o) return 'undefined' == typeof e.getAttribute ? k.prop(e, t, n) : ((1 === o && k.isXMLDoc(e)) || (i = k.attrHooks[t.toLowerCase()] || (k.expr.match.bool.test(t) ? ht : void 0)), void 0 !== n ? null === n ? void k.removeAttr(e, t) : i && 'set' in i && void 0 !== (r = i.set(e, n, t)) ? r : (e.setAttribute(t, n + ''), n) : i && 'get' in i && null !== (r = i.get(e, t)) ? r : null == (r = k.find.attr(e, t)) ? void 0 : r); }, attrHooks: { type: { set: function(e, t) { if (!y.radioValue && 'radio' === t && A(e, 'input')) { var n = e.value; return e.setAttribute('type', t), n && (e.value = n), t; } }, }, }, removeAttr: function(e, t) { var n, r = 0, i = t && t.match(R); if (i && 1 === e.nodeType) while ((n = i[r++])) e.removeAttribute(n); }, }), (ht = { set: function(e, t, n) { return !1 === t ? k.removeAttr(e, n) : e.setAttribute(n, n), n; }, }), k.each(k.expr.match.bool.source.match(/\w+/g), function(e, t) { var a = gt[t] || k.find.attr; gt[t] = function(e, t, n) { var r, i, o = t.toLowerCase(); return n || ((i = gt[o]), (gt[o] = r), (r = null != a(e, t, n) ? o : null), (gt[o] = i)), r; }; }); var vt = /^(?:input|select|textarea|button)$/i, yt = /^(?:a|area)$/i; function mt(e) { return (e.match(R) || []).join(' '); } function xt(e) { return (e.getAttribute && e.getAttribute('class')) || ''; } function bt(e) { return Array.isArray(e) ? e : ('string' == typeof e && e.match(R)) || []; } k.fn.extend({ prop: function(e, t) { return _(this, k.prop, e, t, 1 < arguments.length); }, removeProp: function(e) { return this.each(function() { delete this[k.propFix[e] || e]; }); }, }), k.extend({ prop: function(e, t, n) { var r, i, o = e.nodeType; if (3 !== o && 8 !== o && 2 !== o) return ( (1 === o && k.isXMLDoc(e)) || ((t = k.propFix[t] || t), (i = k.propHooks[t])), void 0 !== n ? i && 'set' in i && void 0 !== (r = i.set(e, n, t)) ? r : (e[t] = n) : i && 'get' in i && null !== (r = i.get(e, t)) ? r : e[t] ); }, propHooks: { tabIndex: { get: function(e) { var t = k.find.attr(e, 'tabindex'); return t ? parseInt(t, 10) : vt.test(e.nodeName) || (yt.test(e.nodeName) && e.href) ? 0 : -1; }, }, }, propFix: { for: 'htmlFor', class: 'className' }, }), y.optSelected || (k.propHooks.selected = { get: function(e) { var t = e.parentNode; return t && t.parentNode && t.parentNode.selectedIndex, null; }, set: function(e) { var t = e.parentNode; t && (t.selectedIndex, t.parentNode && t.parentNode.selectedIndex); }, }), k.each( [ 'tabIndex', 'readOnly', 'maxLength', 'cellSpacing', 'cellPadding', 'rowSpan', 'colSpan', 'useMap', 'frameBorder', 'contentEditable', ], function() { k.propFix[this.toLowerCase()] = this; }, ), k.fn.extend({ addClass: function(t) { var e, n, r, i, o, a, s, u = 0; if (m(t)) return this.each(function(e) { k(this).addClass(t.call(this, e, xt(this))); }); if ((e = bt(t)).length) while ((n = this[u++])) if (((i = xt(n)), (r = 1 === n.nodeType && ' ' + mt(i) + ' '))) { a = 0; while ((o = e[a++])) r.indexOf(' ' + o + ' ') < 0 && (r += o + ' '); i !== (s = mt(r)) && n.setAttribute('class', s); } return this; }, removeClass: function(t) { var e, n, r, i, o, a, s, u = 0; if (m(t)) return this.each(function(e) { k(this).removeClass(t.call(this, e, xt(this))); }); if (!arguments.length) return this.attr('class', ''); if ((e = bt(t)).length) while ((n = this[u++])) if (((i = xt(n)), (r = 1 === n.nodeType && ' ' + mt(i) + ' '))) { a = 0; while ((o = e[a++])) while (-1 < r.indexOf(' ' + o + ' ')) r = r.replace(' ' + o + ' ', ' '); i !== (s = mt(r)) && n.setAttribute('class', s); } return this; }, toggleClass: function(i, t) { var o = typeof i, a = 'string' === o || Array.isArray(i); return 'boolean' == typeof t && a ? t ? this.addClass(i) : this.removeClass(i) : m(i) ? this.each(function(e) { k(this).toggleClass(i.call(this, e, xt(this), t), t); }) : this.each(function() { var e, t, n, r; if (a) { (t = 0), (n = k(this)), (r = bt(i)); while ((e = r[t++])) n.hasClass(e) ? n.removeClass(e) : n.addClass(e); } else (void 0 !== i && 'boolean' !== o) || ((e = xt(this)) && Q.set(this, '__className__', e), this.setAttribute && this.setAttribute('class', e || !1 === i ? '' : Q.get(this, '__className__') || '')); }); }, hasClass: function(e) { var t, n, r = 0; t = ' ' + e + ' '; while ((n = this[r++])) if (1 === n.nodeType && -1 < (' ' + mt(xt(n)) + ' ').indexOf(t)) return !0; return !1; }, }); var wt = /\r/g; k.fn.extend({ val: function(n) { var r, e, i, t = this[0]; return arguments.length ? ((i = m(n)), this.each(function(e) { var t; 1 === this.nodeType && (null == (t = i ? n.call(this, e, k(this).val()) : n) ? (t = '') : 'number' == typeof t ? (t += '') : Array.isArray(t) && (t = k.map(t, function(e) { return null == e ? '' : e + ''; })), ((r = k.valHooks[this.type] || k.valHooks[this.nodeName.toLowerCase()]) && 'set' in r && void 0 !== r.set(this, t, 'value')) || (this.value = t)); })) : t ? (r = k.valHooks[t.type] || k.valHooks[t.nodeName.toLowerCase()]) && 'get' in r && void 0 !== (e = r.get(t, 'value')) ? e : 'string' == typeof (e = t.value) ? e.replace(wt, '') : null == e ? '' : e : void 0; }, }), k.extend({ valHooks: { option: { get: function(e) { var t = k.find.attr(e, 'value'); return null != t ? t : mt(k.text(e)); }, }, select: { get: function(e) { var t, n, r, i = e.options, o = e.selectedIndex, a = 'select-one' === e.type, s = a ? null : [], u = a ? o + 1 : i.length; for (r = o < 0 ? u : a ? o : 0; r < u; r++) if ( ((n = i[r]).selected || r === o) && !n.disabled && (!n.parentNode.disabled || !A(n.parentNode, 'optgroup')) ) { if (((t = k(n).val()), a)) return t; s.push(t); } return s; }, set: function(e, t) { var n, r, i = e.options, o = k.makeArray(t), a = i.length; while (a--) ((r = i[a]).selected = -1 < k.inArray(k.valHooks.option.get(r), o)) && (n = !0); return n || (e.selectedIndex = -1), o; }, }, }, }), k.each(['radio', 'checkbox'], function() { (k.valHooks[this] = { set: function(e, t) { if (Array.isArray(t)) return (e.checked = -1 < k.inArray(k(e).val(), t)); }, }), y.checkOn || (k.valHooks[this].get = function(e) { return null === e.getAttribute('value') ? 'on' : e.value; }); }), (y.focusin = 'onfocusin' in C); var Tt = /^(?:focusinfocus|focusoutblur)$/, Ct = function(e) { e.stopPropagation(); }; k.extend(k.event, { trigger: function(e, t, n, r) { var i, o, a, s, u, l, c, f, p = [n || E], d = v.call(e, 'type') ? e.type : e, h = v.call(e, 'namespace') ? e.namespace.split('.') : []; if ( ((o = f = a = n = n || E), 3 !== n.nodeType && 8 !== n.nodeType && !Tt.test(d + k.event.triggered) && (-1 < d.indexOf('.') && ((d = (h = d.split('.')).shift()), h.sort()), (u = d.indexOf(':') < 0 && 'on' + d), ((e = e[k.expando] ? e : new k.Event(d, 'object' == typeof e && e)).isTrigger = r ? 2 : 3), (e.namespace = h.join('.')), (e.rnamespace = e.namespace ? new RegExp('(^|\\.)' + h.join('\\.(?:.*\\.|)') + '(\\.|$)') : null), (e.result = void 0), e.target || (e.target = n), (t = null == t ? [e] : k.makeArray(t, [e])), (c = k.event.special[d] || {}), r || !c.trigger || !1 !== c.trigger.apply(n, t))) ) { if (!r && !c.noBubble && !x(n)) { for (s = c.delegateType || d, Tt.test(s + d) || (o = o.parentNode); o; o = o.parentNode) p.push(o), (a = o); a === (n.ownerDocument || E) && p.push(a.defaultView || a.parentWindow || C); } i = 0; while ((o = p[i++]) && !e.isPropagationStopped()) (f = o), (e.type = 1 < i ? s : c.bindType || d), (l = (Q.get(o, 'events') || {})[e.type] && Q.get(o, 'handle')) && l.apply(o, t), (l = u && o[u]) && l.apply && G(o) && ((e.result = l.apply(o, t)), !1 === e.result && e.preventDefault()); return ( (e.type = d), r || e.isDefaultPrevented() || (c._default && !1 !== c._default.apply(p.pop(), t)) || !G(n) || (u && m(n[d]) && !x(n) && ((a = n[u]) && (n[u] = null), (k.event.triggered = d), e.isPropagationStopped() && f.addEventListener(d, Ct), n[d](), e.isPropagationStopped() && f.removeEventListener(d, Ct), (k.event.triggered = void 0), a && (n[u] = a))), e.result ); } }, simulate: function(e, t, n) { var r = k.extend(new k.Event(), n, { type: e, isSimulated: !0 }); k.event.trigger(r, null, t); }, }), k.fn.extend({ trigger: function(e, t) { return this.each(function() { k.event.trigger(e, t, this); }); }, triggerHandler: function(e, t) { var n = this[0]; if (n) return k.event.trigger(e, t, n, !0); }, }), y.focusin || k.each({ focus: 'focusin', blur: 'focusout' }, function(n, r) { var i = function(e) { k.event.simulate(r, e.target, k.event.fix(e)); }; k.event.special[r] = { setup: function() { var e = this.ownerDocument || this, t = Q.access(e, r); t || e.addEventListener(n, i, !0), Q.access(e, r, (t || 0) + 1); }, teardown: function() { var e = this.ownerDocument || this, t = Q.access(e, r) - 1; t ? Q.access(e, r, t) : (e.removeEventListener(n, i, !0), Q.remove(e, r)); }, }; }); var Et = C.location, kt = Date.now(), St = /\?/; k.parseXML = function(e) { var t; if (!e || 'string' != typeof e) return null; try { t = new C.DOMParser().parseFromString(e, 'text/xml'); } catch (e) { t = void 0; } return (t && !t.getElementsByTagName('parsererror').length) || k.error('Invalid XML: ' + e), t; }; var Nt = /\[\]$/, At = /\r?\n/g, Dt = /^(?:submit|button|image|reset|file)$/i, jt = /^(?:input|select|textarea|keygen)/i; function qt(n, e, r, i) { var t; if (Array.isArray(e)) k.each(e, function(e, t) { r || Nt.test(n) ? i(n, t) : qt(n + '[' + ('object' == typeof t && null != t ? e : '') + ']', t, r, i); }); else if (r || 'object' !== w(e)) i(n, e); else for (t in e) qt(n + '[' + t + ']', e[t], r, i); } (k.param = function(e, t) { var n, r = [], i = function(e, t) { var n = m(t) ? t() : t; r[r.length] = encodeURIComponent(e) + '=' + encodeURIComponent(null == n ? '' : n); }; if (null == e) return ''; if (Array.isArray(e) || (e.jquery && !k.isPlainObject(e))) k.each(e, function() { i(this.name, this.value); }); else for (n in e) qt(n, e[n], t, i); return r.join('&'); }), k.fn.extend({ serialize: function() { return k.param(this.serializeArray()); }, serializeArray: function() { return this.map(function() { var e = k.prop(this, 'elements'); return e ? k.makeArray(e) : this; }) .filter(function() { var e = this.type; return ( this.name && !k(this).is(':disabled') && jt.test(this.nodeName) && !Dt.test(e) && (this.checked || !pe.test(e)) ); }) .map(function(e, t) { var n = k(this).val(); return null == n ? null : Array.isArray(n) ? k.map(n, function(e) { return { name: t.name, value: e.replace(At, '\r\n') }; }) : { name: t.name, value: n.replace(At, '\r\n') }; }) .get(); }, }); var Lt = /%20/g, Ht = /#.*$/, Ot = /([?&])_=[^&]*/, Pt = /^(.*?):[ \t]*([^\r\n]*)$/gm, Rt = /^(?:GET|HEAD)$/, Mt = /^\/\//, It = {}, Wt = {}, $t = '*/'.concat('*'), Ft = E.createElement('a'); function Bt(o) { return function(e, t) { 'string' != typeof e && ((t = e), (e = '*')); var n, r = 0, i = e.toLowerCase().match(R) || []; if (m(t)) while ((n = i[r++])) '+' === n[0] ? ((n = n.slice(1) || '*'), (o[n] = o[n] || []).unshift(t)) : (o[n] = o[n] || []).push(t); }; } function _t(t, i, o, a) { var s = {}, u = t === Wt; function l(e) { var r; return ( (s[e] = !0), k.each(t[e] || [], function(e, t) { var n = t(i, o, a); return 'string' != typeof n || u || s[n] ? u ? !(r = n) : void 0 : (i.dataTypes.unshift(n), l(n), !1); }), r ); } return l(i.dataTypes[0]) || (!s['*'] && l('*')); } function zt(e, t) { var n, r, i = k.ajaxSettings.flatOptions || {}; for (n in t) void 0 !== t[n] && ((i[n] ? e : r || (r = {}))[n] = t[n]); return r && k.extend(!0, e, r), e; } (Ft.href = Et.href), k.extend({ active: 0, lastModified: {}, etag: {}, ajaxSettings: { url: Et.href, type: 'GET', isLocal: /^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol), global: !0, processData: !0, async: !0, contentType: 'application/x-www-form-urlencoded; charset=UTF-8', accepts: { '*': $t, text: 'text/plain', html: 'text/html', xml: 'application/xml, text/xml', json: 'application/json, text/javascript', }, contents: { xml: /\bxml\b/, html: /\bhtml/, json: /\bjson\b/ }, responseFields: { xml: 'responseXML', text: 'responseText', json: 'responseJSON' }, converters: { '* text': String, 'text html': !0, 'text json': JSON.parse, 'text xml': k.parseXML, }, flatOptions: { url: !0, context: !0 }, }, ajaxSetup: function(e, t) { return t ? zt(zt(e, k.ajaxSettings), t) : zt(k.ajaxSettings, e); }, ajaxPrefilter: Bt(It), ajaxTransport: Bt(Wt), ajax: function(e, t) { 'object' == typeof e && ((t = e), (e = void 0)), (t = t || {}); var c, f, p, n, d, r, h, g, i, o, v = k.ajaxSetup({}, t), y = v.context || v, m = v.context && (y.nodeType || y.jquery) ? k(y) : k.event, x = k.Deferred(), b = k.Callbacks('once memory'), w = v.statusCode || {}, a = {}, s = {}, u = 'canceled', T = { readyState: 0, getResponseHeader: function(e) { var t; if (h) { if (!n) { n = {}; while ((t = Pt.exec(p))) n[t[1].toLowerCase() + ' '] = (n[t[1].toLowerCase() + ' '] || []).concat(t[2]); } t = n[e.toLowerCase() + ' ']; } return null == t ? null : t.join(', '); }, getAllResponseHeaders: function() { return h ? p : null; }, setRequestHeader: function(e, t) { return ( null == h && ((e = s[e.toLowerCase()] = s[e.toLowerCase()] || e), (a[e] = t)), this ); }, overrideMimeType: function(e) { return null == h && (v.mimeType = e), this; }, statusCode: function(e) { var t; if (e) if (h) T.always(e[T.status]); else for (t in e) w[t] = [w[t], e[t]]; return this; }, abort: function(e) { var t = e || u; return c && c.abort(t), l(0, t), this; }, }; if ( (x.promise(T), (v.url = ((e || v.url || Et.href) + '').replace(Mt, Et.protocol + '//')), (v.type = t.method || t.type || v.method || v.type), (v.dataTypes = (v.dataType || '*').toLowerCase().match(R) || ['']), null == v.crossDomain) ) { r = E.createElement('a'); try { (r.href = v.url), (r.href = r.href), (v.crossDomain = Ft.protocol + '//' + Ft.host != r.protocol + '//' + r.host); } catch (e) { v.crossDomain = !0; } } if ( (v.data && v.processData && 'string' != typeof v.data && (v.data = k.param(v.data, v.traditional)), _t(It, v, t, T), h) ) return T; for (i in ((g = k.event && v.global) && 0 == k.active++ && k.event.trigger('ajaxStart'), (v.type = v.type.toUpperCase()), (v.hasContent = !Rt.test(v.type)), (f = v.url.replace(Ht, '')), v.hasContent ? v.data && v.processData && 0 === (v.contentType || '').indexOf('application/x-www-form-urlencoded') && (v.data = v.data.replace(Lt, '+')) : ((o = v.url.slice(f.length)), v.data && (v.processData || 'string' == typeof v.data) && ((f += (St.test(f) ? '&' : '?') + v.data), delete v.data), !1 === v.cache && ((f = f.replace(Ot, '$1')), (o = (St.test(f) ? '&' : '?') + '_=' + kt++ + o)), (v.url = f + o)), v.ifModified && (k.lastModified[f] && T.setRequestHeader('If-Modified-Since', k.lastModified[f]), k.etag[f] && T.setRequestHeader('If-None-Match', k.etag[f])), ((v.data && v.hasContent && !1 !== v.contentType) || t.contentType) && T.setRequestHeader('Content-Type', v.contentType), T.setRequestHeader( 'Accept', v.dataTypes[0] && v.accepts[v.dataTypes[0]] ? v.accepts[v.dataTypes[0]] + ('*' !== v.dataTypes[0] ? ', ' + $t + '; q=0.01' : '') : v.accepts['*'], ), v.headers)) T.setRequestHeader(i, v.headers[i]); if (v.beforeSend && (!1 === v.beforeSend.call(y, T, v) || h)) return T.abort(); if ( ((u = 'abort'), b.add(v.complete), T.done(v.success), T.fail(v.error), (c = _t(Wt, v, t, T))) ) { if (((T.readyState = 1), g && m.trigger('ajaxSend', [T, v]), h)) return T; v.async && 0 < v.timeout && (d = C.setTimeout(function() { T.abort('timeout'); }, v.timeout)); try { (h = !1), c.send(a, l); } catch (e) { if (h) throw e; l(-1, e); } } else l(-1, 'No Transport'); function l(e, t, n, r) { var i, o, a, s, u, l = t; h || ((h = !0), d && C.clearTimeout(d), (c = void 0), (p = r || ''), (T.readyState = 0 < e ? 4 : 0), (i = (200 <= e && e < 300) || 304 === e), n && (s = (function(e, t, n) { var r, i, o, a, s = e.contents, u = e.dataTypes; while ('*' === u[0]) u.shift(), void 0 === r && (r = e.mimeType || t.getResponseHeader('Content-Type')); if (r) for (i in s) if (s[i] && s[i].test(r)) { u.unshift(i); break; } if (u[0] in n) o = u[0]; else { for (i in n) { if (!u[0] || e.converters[i + ' ' + u[0]]) { o = i; break; } a || (a = i); } o = o || a; } if (o) return o !== u[0] && u.unshift(o), n[o]; })(v, T, n)), (s = (function(e, t, n, r) { var i, o, a, s, u, l = {}, c = e.dataTypes.slice(); if (c[1]) for (a in e.converters) l[a.toLowerCase()] = e.converters[a]; o = c.shift(); while (o) if ( (e.responseFields[o] && (n[e.responseFields[o]] = t), !u && r && e.dataFilter && (t = e.dataFilter(t, e.dataType)), (u = o), (o = c.shift())) ) if ('*' === o) o = u; else if ('*' !== u && u !== o) { if (!(a = l[u + ' ' + o] || l['* ' + o])) for (i in l) if ( (s = i.split(' '))[1] === o && (a = l[u + ' ' + s[0]] || l['* ' + s[0]]) ) { !0 === a ? (a = l[i]) : !0 !== l[i] && ((o = s[0]), c.unshift(s[1])); break; } if (!0 !== a) if (a && e['throws']) t = a(t); else try { t = a(t); } catch (e) { return { state: 'parsererror', error: a ? e : 'No conversion from ' + u + ' to ' + o, }; } } return { state: 'success', data: t }; })(v, s, T, i)), i ? (v.ifModified && ((u = T.getResponseHeader('Last-Modified')) && (k.lastModified[f] = u), (u = T.getResponseHeader('etag')) && (k.etag[f] = u)), 204 === e || 'HEAD' === v.type ? (l = 'nocontent') : 304 === e ? (l = 'notmodified') : ((l = s.state), (o = s.data), (i = !(a = s.error)))) : ((a = l), (!e && l) || ((l = 'error'), e < 0 && (e = 0))), (T.status = e), (T.statusText = (t || l) + ''), i ? x.resolveWith(y, [o, l, T]) : x.rejectWith(y, [T, l, a]), T.statusCode(w), (w = void 0), g && m.trigger(i ? 'ajaxSuccess' : 'ajaxError', [T, v, i ? o : a]), b.fireWith(y, [T, l]), g && (m.trigger('ajaxComplete', [T, v]), --k.active || k.event.trigger('ajaxStop'))); } return T; }, getJSON: function(e, t, n) { return k.get(e, t, n, 'json'); }, getScript: function(e, t) { return k.get(e, void 0, t, 'script'); }, }), k.each(['get', 'post'], function(e, i) { k[i] = function(e, t, n, r) { return ( m(t) && ((r = r || n), (n = t), (t = void 0)), k.ajax( k.extend( { url: e, type: i, dataType: r, data: t, success: n }, k.isPlainObject(e) && e, ), ) ); }; }), (k._evalUrl = function(e, t) { return k.ajax({ url: e, type: 'GET', dataType: 'script', cache: !0, async: !1, global: !1, converters: { 'text script': function() {} }, dataFilter: function(e) { k.globalEval(e, t); }, }); }), k.fn.extend({ wrapAll: function(e) { var t; return ( this[0] && (m(e) && (e = e.call(this[0])), (t = k(e, this[0].ownerDocument) .eq(0) .clone(!0)), this[0].parentNode && t.insertBefore(this[0]), t .map(function() { var e = this; while (e.firstElementChild) e = e.firstElementChild; return e; }) .append(this)), this ); }, wrapInner: function(n) { return m(n) ? this.each(function(e) { k(this).wrapInner(n.call(this, e)); }) : this.each(function() { var e = k(this), t = e.contents(); t.length ? t.wrapAll(n) : e.append(n); }); }, wrap: function(t) { var n = m(t); return this.each(function(e) { k(this).wrapAll(n ? t.call(this, e) : t); }); }, unwrap: function(e) { return ( this.parent(e) .not('body') .each(function() { k(this).replaceWith(this.childNodes); }), this ); }, }), (k.expr.pseudos.hidden = function(e) { return !k.expr.pseudos.visible(e); }), (k.expr.pseudos.visible = function(e) { return !!(e.offsetWidth || e.offsetHeight || e.getClientRects().length); }), (k.ajaxSettings.xhr = function() { try { return new C.XMLHttpRequest(); } catch (e) {} }); var Ut = { 0: 200, 1223: 204 }, Xt = k.ajaxSettings.xhr(); (y.cors = !!Xt && 'withCredentials' in Xt), (y.ajax = Xt = !!Xt), k.ajaxTransport(function(i) { var o, a; if (y.cors || (Xt && !i.crossDomain)) return { send: function(e, t) { var n, r = i.xhr(); if ((r.open(i.type, i.url, i.async, i.username, i.password), i.xhrFields)) for (n in i.xhrFields) r[n] = i.xhrFields[n]; for (n in (i.mimeType && r.overrideMimeType && r.overrideMimeType(i.mimeType), i.crossDomain || e['X-Requested-With'] || (e['X-Requested-With'] = 'XMLHttpRequest'), e)) r.setRequestHeader(n, e[n]); (o = function(e) { return function() { o && ((o = a = r.onload = r.onerror = r.onabort = r.ontimeout = r.onreadystatechange = null), 'abort' === e ? r.abort() : 'error' === e ? 'number' != typeof r.status ? t(0, 'error') : t(r.status, r.statusText) : t( Ut[r.status] || r.status, r.statusText, 'text' !== (r.responseType || 'text') || 'string' != typeof r.responseText ? { binary: r.response } : { text: r.responseText }, r.getAllResponseHeaders(), )); }; }), (r.onload = o()), (a = r.onerror = r.ontimeout = o('error')), void 0 !== r.onabort ? (r.onabort = a) : (r.onreadystatechange = function() { 4 === r.readyState && C.setTimeout(function() { o && a(); }); }), (o = o('abort')); try { r.send((i.hasContent && i.data) || null); } catch (e) { if (o) throw e; } }, abort: function() { o && o(); }, }; }), k.ajaxPrefilter(function(e) { e.crossDomain && (e.contents.script = !1); }), k.ajaxSetup({ accepts: { script: 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript', }, contents: { script: /\b(?:java|ecma)script\b/ }, converters: { 'text script': function(e) { return k.globalEval(e), e; }, }, }), k.ajaxPrefilter('script', function(e) { void 0 === e.cache && (e.cache = !1), e.crossDomain && (e.type = 'GET'); }), k.ajaxTransport('script', function(n) { var r, i; if (n.crossDomain || n.scriptAttrs) return { send: function(e, t) { (r = k('